JavascriptProva

lunedì 30 gennaio 2012

Dragdrop piuttosto elegante, tramite innesco di evento e passaggio di dati

Credo di aver ottenuto un ottimo risultato:
Questo è il codice della mia funzione, che ho ribattezzato Dragabile, avente per parametri gli id degli elementi HTML che si vogliano rendere suscettibili di trascinamento.
function Dragabile(){
 var nomi=new Array();
 var offsetX;
 var offsetY;
 var startX;
 var startY;
 var dragElement;
 for(n=0;n<arguments.length;n++)
  nomi[n]=arguments[n];
 
 var inizializza=function(){
  document.onmousedown=onMouseDown;
  document.onmouseup=onMouseUp; 
  document.onmouseover=onMouseOver;
 }
 var onMouseOver=function(e){
  for(n=0;n<nomi.length;n++)
   if(e.target.id==nomi[n]) e.target.style.cursor="pointer";
 }
 var onMouseDown=function(e){
  for(n=0;n<nomi.length;n++)
   if(e.target.id==nomi[n]){
    dragElement=e.target;
    offsetX=Nr(dragElement.style.left);
    offsetY=Nr(dragElement.style.top);
    startX=e.clientX;
    startY=e.clientY;
    for (n=0;n<document.getElementsByTagName('*').length;n++){
     document.getElementsByTagName('*')[n].style.zIndex=0;
    }
    dragElement.style.zIndex=1;
    document.onmousemove=onMouseMove;
   }
  return false;   
 }

 var onMouseMove=function(e){
  dragElement.style.left=offsetX+e.clientX-startX;
  dragElement.style.top=offsetY+e.clientY-startY;
 
 }

 var onMouseUp=function(e){
  document.onmousemove=null;
  for(n=0;n<nomi.length;n++)
   if(e.target.id==nomi[n]){
    var event=document.createEvent("Event");
    event.initEvent("Dropped",true,true);
    event.data=new Array(e.target,bersaglio(e));
    window.dispatchEvent(event);
   }
  dragElement=null;
 }
 var bersaglio=function(e){
  var oggetto;
  for(n=0;n<document.getElementsByTagName('*').length;n++){
   sinistra=Nr(document.getElementsByTagName('*')[n].style.left);
   alto=Nr(document.getElementsByTagName('*')[n].style.top);
   destra=sinistra+Nr(document.getElementsByTagName('*')[n].style.width);
   basso=alto+Nr(document.getElementsByTagName('*')[n].style.height);
   if(e.clientX>sinistra && e.clientX<destra && e.clientY>alto && e.clientY<basso)
    if(e.target != document.getElementsByTagName('*')[n])
     oggetto=document.getElementsByTagName('*')[n]
  }
 return oggetto;
 }
 inizializza();     

}
Piuttosto pesante, ma non credo ci sia possibilità di fare molto di meglio, in quanto anche l'autore di uno dei testi che ho trovato via web dice che non esiste altro modo che "scandagliare" il documento alla ricerca di aree occupate da altri oggetti, come fa qui la parte del codice scritta in blu.

Questo è il codice del modulo principale:
<script src="funzioni.js"></script>
<script>

Dragabile("due");
window.addEventListener("Dropped",function(event){event.data[0].innerHTML=event.data[1].id;},false); 
</script>
<body onload="inizia()">
<div id="uno" style="position:absolute;
  width:300px;
  height:100px;
  left:200px;
  top:100px;
  background:#CCFFCC;
  font-size:30px;
  "> 
</div>

<div id="due" style="position:absolute;
  width:300px;
  height:100px;
  left:500px;
  top:100px;
  background:#FFCCCC;
  font-size:30px;
  "> 
</div>
<img id="tre" style="width:300px;height:300px;position:absolute;left:0px;top:10px;" src="pallone.gif" />
</body>
Ecco, la parte scritta in rosso è quella che riceve l'evento una volta che l'elemento trascinabile è stato "droppato", e lo gestisce come meglio le pare a seconda della volontà del programmatore.

Credo che per essere un neofita non avrei potuto fare di meglio...

DragDrop con innesco di un evento e uso del relativo listener.

Ueeee!!! Fantastico!

La mia funzione DragDrop(), avente per parametri un numero variabile di nomi di elementi HTML, provvede egregiamente a rendere trascinabili gli elementi.
Adesso sono riuscito a far sì che l'evento di "droppaggio" dell'elemento inneschi un evento, per cui, ponendone un listener, si può intercettare con eventuali parametri (che ancora non so come inserire nell'evento).

Ecco il codice, un po' rudimentale in certi tratti, comunque l'idea è buona...
function DragDrop(){
 var nomi=new Array();
 var offsetX;
 var offsetY;
 var startX;
 var startY;
 var dragElement;
 for(n=0;n<arguments.length;n++)
  nomi[n]=arguments[n];
 
 var inizializza=function(){
  document.onmousedown=onMouseDown;
  document.onmouseup=onMouseUp; 
  document.onmouseover=onMouseOver;
 }
 var onMouseOver=function(e){
  for(n=0;n<nomi.length;n++)
   if(e.target.id==nomi[n]) e.target.style.cursor="pointer";
 }
 var onMouseDown=function(e){
  for(n=0;n<nomi.length;n++)
   if(e.target.id==nomi[n]){
    dragElement=e.target;
    offsetX=Nr(dragElement.style.left);
    offsetY=Nr(dragElement.style.top);
    startX=e.clientX;
    startY=e.clientY;
    for (n=0;n<document.getElementsByTagName('*').length;n++){
     document.getElementsByTagName('*')[n].style.zIndex=0;
    }
    dragElement.style.zIndex=1;
    document.onmousemove=onMouseMove;
   }
  return false;   
 }

 var onMouseMove=function(e){
  dragElement.style.left=offsetX+e.clientX-startX;
  dragElement.style.top=offsetY+e.clientY-startY;
 
 }

 var onMouseUp=function(e){
  document.onmousemove=null;
  for(n=0;n<nomi.length;n++)
   if(e.target.id==nomi[n]){
    var event=document.createEvent("Event");
    event.initEvent("Dropped",true,true);
    window.dispatchEvent(event);
   }
  dragElement=null;
 }
 inizializza();     

}
Quello in rosso è il codice che crea e triggera l'evento personalizzato "Dropped".
Questo è il codice presente nella mia libreria funzioni.js.
Nel modulo principale, invece, ho aggiunto il listener per questo evento:
<script src="funzioni.js"></script>
<script>

DragDrop("uno","due","tre");
window.addEventListener("Dropped",function(){alert("droppato!!!");},false);
</script>
<body onload="inizia()">
<div id="uno" style="position:absolute;
  width:300px;
  height:100px;
  left:200px;
  top:100px;
  background:green;
  "> 
</div>

<div id="due" style="position:absolute;
  width:300px;
  height:100px;
  left:500px;
  top:100px;
  background:red;
  "> 
</div>
<img id="tre" style="width:300px;position:absolute" src="pallone.gif">
</body>
...e quello in rosso è l'aggiunta dell'ascoltatore o listener.
In sostanza, quando un elemento viene droppato, l'evento si scatena comunque. Sta poi all'eventuale presenza di listeners la facoltà di volerlo intercettare o meno ponendo le necessarie conseguenze.

Lettura del foglio di stile esterno da javaScript

Funziona anche con il foglio di stile esterno, anche se lo scorrimento mi sembra un po' meno fluido...
<html>
<head>
<link rel="stylesheet" type="text/css" href="miostile.css">
<script type="text/javascript">

function Nr(stile){
 var numero=Number(stile.replace("px",""));
 return numero;
}

var oggetto, offsetX, offsetY, startX, startY;
function inizia(){
 document.onmousedown=MouseDown;
 document.onmouseup=MouseUp;
}

function MouseDown(e){
 oggetto=e.target;
 var stile=document.defaultView.getComputedStyle(oggetto,"");
 offsetX=Nr(stile.left);
 offsetY=Nr(stile.top);
 startX=e.clientX;
 startY=e.clientY;
 document.onmousemove=MouseMove;
 return false;
 
}

function MouseMove(e){
 oggetto.style.left=offsetX+e.clientX-startX;
 oggetto.style.top=offsetY+e.clientY-startY;

}

function MouseUp(){
 document.onmousemove=null;
 oggetto=null;
}
  
</script>
</head>

<body onLoad="inizia()">
<div id="uno" class="uno">
</div>

</body>
</html>

Lettura da parte del javaScript della posizione di un elemento impostata tramite un foglio di stile interno

Ecco la soluzione al fatto che il JavaScript non legge i fogli di stile interni:
<html>
<head>
<style>
.uno{
 position:relative;
 left:100px;
 top:50px;
 width:200px;
 height:100px;
 background:#AAFFCC;
 border:10px solid green;
}
</style>
<script type="text/javascript">

function Nr(stile){
 var numero=Number(stile.replace("px",""));
 return numero;
}

var oggetto, offsetX, offsetY, startX, startY;
function inizia(){
 document.onmousedown=MouseDown;
 document.onmouseup=MouseUp;
}

function MouseDown(e){
 oggetto=e.target;
 var stile=document.defaultView.getComputedStyle(oggetto,"");
 offsetX=Nr(stile.left);
 offsetY=Nr(stile.top);
 startX=e.clientX;
 startY=e.clientY;
 document.onmousemove=MouseMove;
 return false;
 
}

function MouseMove(e){
 oggetto.style.left=offsetX+e.clientX-startX;
 oggetto.style.top=offsetY+e.clientY-startY;

}

function MouseUp(){
 document.onmousemove=null;
 oggetto=null;
}
  
</script>
</head>

<body onLoad="inizia()">
<div id="uno" class="uno">
</div>

</body>
</html>
L'aggiunta della riga in rosso e dei valori su fondo giallo risolve il problema.
Come e perchè, ancora non lo capisco con precisione...

JavaScript e fogli di stile

Torno a rielaborare il mio (con l'aiuto di questo ottimo articolo) programmino per "dragare" oggetti.

Ormai credo di padroneggiare abbastanza la tecnica, dato che l'ho riscritto da solo su un altro computer in cui non avevo le mie librerie.

Però mi sono scontrato con un problema relativo ai fogli di stile, perchè le coordinate di un oggetto presenti su un foglio di stile non vengono lette da JavaScript...


Provo a riscrivere di sana pianta il codice per rendere "dragabile" un DIV.
<html>
<head>

<script type="text/javascript">

function Nr(stile){
 var numero=Number(stile.replace("px",""));
 return numero;
}

var oggetto, offsetX, offsetY, startX, startY;
function inizia(){
 document.onmousedown=MouseDown;
 document.onmouseup=MouseUp;
}

function MouseDown(e){
 oggetto=e.target;
 offsetX=Nr(oggetto.style.left);
 offsetY=Nr(oggetto.style.top);
 startX=e.clientX;
 startY=e.clientY;
 document.onmousemove=MouseMove;
 return false;
}

function MouseMove(e){
 oggetto.style.left=offsetX+e.clientX-startX;
 oggetto.style.top=offsetY+e.clientY-startY;

}

function MouseUp(){
 document.onmousemove=null;
 oggetto=null;
}
  
</script>
</head>

<body onLoad="inizia()">
<div id="uno" style= "
   position:relative;
   left:100px;
   top:50px;
   width:200px;
   height:100px;
   background:#AAFFCC;
   border:10px solid green;
   ">
</div>

</body>
</html>
...senza troppe difficoltà, salvo un paio di errori di distrazione per aver scritto un "offsetX" al posto di un "offsetY", e per aver trascurato il parametro e in MouseMove...
Bene: questo codice funziona egregiamente nel portare a spasso il DIV per tutta la finestra del browser.
Ora lo scrivo con un foglio di stile interno...
<html>
<head>
<style>
.uno{
 position:relative;
 left:100px;
 top:50px;
 width:200px;
 height:100px;
 background:#AAFFCC;
 border:10px solid green;
}
</style>
<script type="text/javascript">

function Nr(stile){
 var numero=Number(stile.replace("px",""));
 return numero;
}

var oggetto, offsetX, offsetY, startX, startY;
function inizia(){
 document.onmousedown=MouseDown;
 document.onmouseup=MouseUp;
}

function MouseDown(e){
 oggetto=e.target;
 offsetX=Nr(oggetto.style.left);
 offsetY=Nr(oggetto.style.top);
 startX=e.clientX;
 startY=e.clientY;
 document.onmousemove=MouseMove;
 return false;
}

function MouseMove(e){
 oggetto.style.left=offsetX+e.clientX-startX;
 oggetto.style.top=offsetY+e.clientY-startY;

}

function MouseUp(){
 document.onmousemove=null;
 oggetto=null;
}
  
</script>
</head>

<body onLoad="inizia()">
<div id="uno" class="uno">
</div>

</body>
</html>
E vediamo cosa succede...

Ecco: quando faccio il MouseDown tutto bene... Quando poi inizio il MouseMove il mio DIV mi scatta all'indietro e in alto, andandosi a rifugiare nell'angolo superiore sinistro della finestra.
Perchè?

Con una tecnica molto rudimentale ma efficace, pongo un comando "spia" nel mio codice:
function MouseDown(e){
 oggetto=e.target;
 offsetX=Nr(oggetto.style.left);
 offsetY=Nr(oggetto.style.top);
 startX=e.clientX;
 startY=e.clientY;
 document.onmousemove=MouseMove;
 alert(offsetX+" "+offsetY);
 return false;
}
Questo mi dà il valore delle due variabili in cui va immagazzinata la posizione iniziale del DIV quando si fa il MouseDown su di esso: esso mi risulta, da questa prova pari a 0 e 0. Quindi, non appena faccio il MouseMove, la nuova posizione del DIV mi viene calcolata non a partire dalla posizione iniziale del DIV, ma da zero!
Se ad esempio la posizione X iniziale del DIV è 100, e il mouse si muove di 10, la posizione calcolata nell'ambito del MouseMove dovrebbe essere 100+10=110 perchè in offsetX è stata memorizzata la posizione iniziale del DIV che era 100; se invece in offsetX la posizione iniziale memorizzata è zero, all'atto del MouseMove il calcolo non viene fatto con 100 ma con 0, e quindi il DIV si sposta a una posizione sull'asse delle X di 0+10=10, e non 110!
Sono arrivato alla conclusione che se la posizione del DIV è specificata in un foglio di stile, il codice javaScript non la legge, ponendo quindi nuovi problemi...
A maggior ragione ciò accade con fogli di stile esterni...

domenica 29 gennaio 2012

Studio di createEvent, initMouseEvent, dispatchEvent

Analizziamo questo codice per cercare di ricordarlo meglio...

function evoca(){
 var oggetto=document.getElementById("uno");
 var evento=document.createEvent("MouseEvents")
 evento.initMouseEvent('click', true, true, window, 1, 12, 345, 7, 220, false, false, true, false, 0, null)
 oggetto.dispatchEvent(evento);
}
Si tratta di tre istruzioni:
  • createEvent
  • initMouseEvent
  • dispatchEvent

createEvent è riferito all'oggetto document.
initMouseEvent è riferito all'evento creato.
dispatchEvent è riferito all'oggetto al quale si attribuisce l'evento.
Ora vediamo il parametro di createEvent.
Il parametro di createEvent che ho visto è MouseEvents, che sta per eventi del mouse, dei quali quelli che mi vengono in mente sono click, mousedown, mouseup, mouseover, mouseove, mouseout.

Per quanto riguarda initMouseEvent, che inizializza gli eventi del tipo MouseEvents: Se la scrivo così forse mi viene più facile memorizzare...
evento.initMouseEvent("click",true,true,window,
    1,0,0,0,0,
    false,false,false,false,
    0,null)
Ecco: il primo gruppo riguarda il nome dell'evento, il più facile, e, credo, lo scope dell'evento. In mezzo ci sono valori riguardanti il bubbling e la cancellazione dell'evento, che devo ancora imparare ma che credo si possano lasciare a true.

Il secondo gruppo è fatto da un'informazione chiamata detali e dalle coordinate screenX, screenY, clientX, clientY.

Il terzo gruppo riguarda i tasti da premere insieme al mouse: ctrlKey, altKey, shiftKey, metaKey, e credo possano restare tranquillamente a false.

L'ultimo gruppo è dato dal bottone premuto sul mouse e dal relatedTarget.

Bene... forse è il caso di vedere nei dettagli ogni singola voce. ma per il momento credo sia più pratico esercitarsi a scrivere createEvent e initMouseEvent con una certa scioltezza...

Creare eventi e chiamarli dall'esterno...

La prima parte del codice di cui sopra non serve!
Il fatto che uso addListener aggiunge semplicemente un "ascoltatore" per un evento a un elemento del documento, e basta.

E' come il classico onclick che aggiungo nei tags di ogni elemento della pagina. I vantaggi che sono riuscito a vedere finora sono che la risposta di un elemento a un evento può essere variata a seconda delle esigenze, mettendo o rimuovendo il listener, e che si può aggiungere e togliere il listener a una serie di elementi (dovrebbe esistere anche l'istruzione per rimuoverlo, suppongo!)

Ora invece sono riuscito a far funzionare un codice che crea un evento.
E' piuttosto complicato.

<html>
<head>

<script type="text/javascript">
function evoca(){
 var oggetto=document.getElementById("uno");
 var evento=document.createEvent("MouseEvents")
 evento.initMouseEvent('click', true, true, window, 1, 12, 345, 7, 220, false, false, true, false, 0, null)
 oggetto.dispatchEvent(evento);
}
</script>
</head>

<body>
<div id="uno" style="background:green;width:100px;height:100px" onClick="alert('cliccato')"></div>
<div id="due" style="background:cyan;width:200px;height:100px;position:absolute;left:200px;top:10px" onMouseOver="evoca();"></div>
</body>
</html>
Ecco, in questo codice il DIV "uno" ha già un evento onClick. Il codice che ho marcato in rosso serve a simulare il click su quell'elemento. Tutto qua.
Se poi il codice viene chiamato da un altro evento in un altro elemento, allora posso simulare l'evento stesso, come in questo caso dove simulo un click sul DIV "uno" passando il mouse sul DIV "due".

Iniziamo ad approfondire gli eventi...

Di palo in frasca, nel mio stile.

Per incapsulare bene il mio codice del drag-drop mi serve che la funzione evochi un evento.
Poi sta al programma ascoltare o meno l'evento.

Mi serve approfondire gli eventi.


Ecco costruito faticosamente un codice per la creazione di un evento e di un listener:
<html>
<head>

<script type="text/javascript">
function simulaClick(){
 var evento=document.createEvent("MouseEvents");
 evento.initMouseEvent("click",true,true,window,0,0,0,0,0,false,false,false,false,0,null)
 event.target.dispatchEvent(evento)
}

function load(){
 var elemento=document.getElementById("uno");
 elemento.addEventListener("click",function(){alert("evento")},true);
}

</script>
</head>

<body onLoad="load()">
<div id="uno" style="background:green;width:100px;height:100px"></div>
</body>
</html>
Non ci ho poi capito molto: l'unica cosa che ho capito è che con la funzione simulaClick viene creato un evento, e che con la funzione load, che viene chiamata all'atto del caricamento del documento, si attribuisce l'ascoltatore dell'evento al div chiamato "uno".

Funziona.
Ora creo due DIV e attribuisco l'ascoltatore all'uno o all'altro...
<html>
<head>

<script type="text/javascript">
function simulaClick(){
 var evento=document.createEvent("MouseEvents");
 evento.initMouseEvent("click",true,true,window,0,0,0,0,0,false,false,false,false,0,null)
 event.target.dispatchEvent(evento)
}

function load(){
 var elemento=document.getElementById("uno");
 elemento.addEventListener("click",function(){alert("evento")},true);
}

</script>
</head>

<body onLoad="load()">
<div id="uno" style="background:green;width:100px;height:100px"></div>
<div id="due" style="background:cyan;width:200px;height:100px;position:absolute;left:200px;top:10px"></div>
</body>
</html>
Ecco, ora ho messo un altro DIV. L'ascoltatore è sempre attribuito al DIV "uno".

Ora lo attribuisco solo al DIV "due".
<html>
<head>

<script type="text/javascript">
function simulaClick(){
 var evento=document.createEvent("MouseEvents");
 evento.initMouseEvent("click",true,true,window,0,0,0,0,0,false,false,false,false,0,null)
 event.target.dispatchEvent(evento)
}

function load(){
 var elemento=document.getElementById("due");
 elemento.addEventListener("click",function(){alert("evento")},true);
}

</script>
</head>

<body onLoad="load()">
<div id="uno" style="background:green;width:100px;height:100px"></div>
<div id="due" style="background:cyan;width:200px;height:100px;position:absolute;left:200px;top:10px"></div>
</body>
</html>
E in effetti, adesso funziona solo se clicco sul DIV "due".

Ora lo attribuisco a tutti e due:
<html>
<head>

<script type="text/javascript">
function simulaClick(){
 var evento=document.createEvent("MouseEvents");
 evento.initMouseEvent("click",true,true,window,0,0,0,0,0,false,false,false,false,0,null)
 event.target.dispatchEvent(evento)
}

function load(){
 var elemento=document.getElementById("uno");
 elemento.addEventListener("click",function(){alert("evento")},true);
 var elemento=document.getElementById("due");
 elemento.addEventListener("click",function(){alert("evento")},true);
}

</script>
</head>

<body onLoad="load()">
<div id="uno" style="background:green;width:100px;height:100px"></div>
<div id="due" style="background:cyan;width:200px;height:100px;position:absolute;left:200px;top:10px"></div>
</body>
</html>
S', funziona!
Inizio a capire qualcosina... ancora poco ma si amplierà!

sabato 28 gennaio 2012

Perfezionando il dragdrop personalizzato...

Ecco, cerco di rendere flessibile il mio codice per riconoscere la destinazione del drag-drop.

<script>
var $=function(id){return document.getElementById(id)}
function Nr(stile){
 numero=Number(stile.replace("px",""));
 return numero;
 }
function DragDrop(){
 var nomi=new Array();
 var offsetX;
 var offsetY;
 var startX;
 var startY;
 var dragElement;
 for(n=0;n<arguments.length;n++)
  nomi[n]=arguments[n];
 
 var inizializza=function(){
  document.onmousedown=onMouseDown;
  document.onmouseup=onMouseUp; 
  document.onmouseover=onMouseOver;
 }
 var onMouseOver=function(e){
  for(n=0;n<nomi.length;n++)
   if(e.target.id==nomi[n]) e.target.style.cursor="pointer";
 }
 var onMouseDown=function(e){
  for(n=0;n<nomi.length;n++)
   if(e.target.id==nomi[n]){
    dragElement=e.target;
    offsetX=Nr(dragElement.style.left);
    offsetY=Nr(dragElement.style.top);
    startX=e.clientX;
    startY=e.clientY;
    for (n=0;n<document.getElementsByTagName('*').length;n++){
     document.getElementsByTagName('*')[n].style.zIndex=0;
    }
    dragElement.style.zIndex=1;
    document.onmousemove=onMouseMove;
   }
  return false;   
 }

 var onMouseMove=function(e){
  dragElement.style.left=offsetX+e.clientX-startX;
  dragElement.style.top=offsetY+e.clientY-startY;
 
 }

 var onMouseUp=function(e){
  document.onmousemove=null;
  for(n=0;n<nomi.length;n++)
   if(e.target.id==nomi[n])
    dropped(e);
  dragElement=null;
 }
 inizializza();     

}
DragDrop("uno");

function Belongs(e){
 var nomi=new Array();
 for(n=1;n<arguments.length;n++)
  nomi[n]=arguments[n];
 for(n=1;n<nomi.length;n++){
  sinistra=Nr(document.getElementById(nomi[n]).style.left);
  alto=Nr(document.getElementById(nomi[n]).style.top);
  destra=sinistra+Nr(document.getElementById(nomi[n]).style.width);
  basso=alto+Nr(document.getElementById(nomi[n]).style.height);
  if(e.clientX>sinistra && e.clientX<destra && e.clientY>alto && e.clientY<basso)
   e.target.innerHTML=nomi[n];
   
 }
 
}
function dropped(e){
 Belongs(e,"due","tre","quattro");
 
}


</script>
<body>
<div id="uno" style="position:absolute;width:300px;height:150px;left:100px;top:100px;border:5px solid green;font-size:30px"></div>
<div id="due" style="position:absolute;width:400px;height:400px;left:600px;top:100pz;background:red"></div>
<div id="tre" style="position:absolute;width:300px;height:200px;left:100px;top:500px;background:blue"></div>
<div id="quattro" style="position:absolute;width:400px;height:200px;left:700px;top:500px;background:yellow"></div>
</body>
Non sono ancora molto soddisfatto...

Riconoscere il drop (tentativo rudimentale riuscito)

Bene. Sono riuscito a crearmi un sistema di riconoscimento dell'oggetto sul quale viene droppato un DIV.
E' ancora molto rudimentale, ma il bello è che è tutto mio (ovviamente con le dovute ispirazioni prese da tutorial vari in rete!

<script>

function Nr(stile){
 numero=Number(stile.replace("px",""));
 return numero;
 }
function DragDrop(){
 var nomi=new Array();
 var offsetX;
 var offsetY;
 var startX;
 var startY;
 var dragElement;
 for(n=0;n<arguments.length;n++)
  nomi[n]=arguments[n];
 
 var inizializza=function(){
  document.onmousedown=onMouseDown;
  document.onmouseup=onMouseUp; 
  document.onmouseover=onMouseOver;
 }
 var onMouseOver=function(e){
  for(n=0;n<nomi.length;n++)
   if(e.target.id==nomi[n]) e.target.style.cursor="pointer";
 }
 var onMouseDown=function(e){
  for(n=0;n<nomi.length;n++)
   if(e.target.id==nomi[n]){
    dragElement=e.target;
    offsetX=Nr(dragElement.style.left);
    offsetY=Nr(dragElement.style.top);
    startX=e.clientX;
    startY=e.clientY;
    for (n=0;n<document.getElementsByTagName('*').length;n++){
     document.getElementsByTagName('*')[n].style.zIndex=0;
    }
    dragElement.style.zIndex=1;
    document.onmousemove=onMouseMove;
   }
  return false;   
 }

 var onMouseMove=function(e){
  dragElement.style.left=offsetX+e.clientX-startX;
  dragElement.style.top=offsetY+e.clientY-startY;
 
 }

 var onMouseUp=function(e){
  document.onmousemove=null;
  for(n=0;n<nomi.length;n++)
   if(e.target.id==nomi[n])
    dropped(e);
  dragElement=null;
 }
 inizializza();     

}
DragDrop("uno");

function Belongs(e,nome){
 sinistra=Nr(nome.style.left);
 alto=Nr(nome.style.top);
 destra=sinistra+Nr(nome.style.width);
 basso=alto+Nr(nome.style.height);
 if(e.clientX>sinistra && e.clientX<destra && e.clientY>alto && e.clientY<basso){
  e.target.innerHTML=nome.id;
 }
}
function dropped(e){
 for(n=0;n<document.getElementsByTagName("div").length;n++)
  if(document.getElementsByTagName("div")[n] != e.target)
   Belongs(e,document.getElementsByTagName("div")[n]);
 
}


</script>
<body>
<div id="uno" style="position:absolute;width:300px;height:150px;left:100px;top:100px;border:5px solid green;font-size:30px"></div>
<div id="due" style="position:absolute;width:400px;height:400px;left:600px;top:100pz;background:red"></div>
<div id="tre" style="position:absolute;width:300px;height:200px;left:100px;top:500px;background:blue"
</body>

mercoledì 25 gennaio 2012

La manuccia come puntatore per gli elementi dragabili

Un perfezionamento: se l'elemento è "dragabile" appare la "manuccia" al posto della freccetta come puntatore del mouse:
function DragDrop(){
 var nomi=new Array();
 var offsetX;
 var offsetY;
 var startX;
 var startY;
 var dragElement;
 for(n=0;n<arguments.length;n++)
  nomi[n]=arguments[n];
 
 var inizializza=function(){
  document.onmousedown=onMouseDown;
  document.onmouseup=onMouseUp; 
  document.onmouseover=onMouseOver;
 }
 var onMouseOver=function(e){
  for(n=0;n<nomi.length;n++)
   if(e.target.id==nomi[n]) e.target.style.cursor="pointer";
 }
 var onMouseDown=function(e){
  for(n=0;n<nomi.length;n++)
   if(e.target.id==nomi[n]){
    dragElement=e.target;
    offsetX=ExtractNumber(dragElement.style.left);
    offsetY=ExtractNumber(dragElement.style.top);
    startX=e.clientX;
    startY=e.clientY;
    for (n=0;n<document.getElementsByTagName('*').length;n++){
     document.getElementsByTagName('*')[n].style.zIndex=0;
    }
    dragElement.style.zIndex=1;
    document.onmousemove=onMouseMove;
   }
  return false;   
 }

 var onMouseMove=function(e){
  dragElement.style.left=offsetX+e.clientX-startX;
  dragElement.style.top=offsetY+e.clientY-startY;
 }

 var onMouseUp=function(){
  document.onmousemove=null;
  dragElement=null; 
 }
 inizializza();     

}

DragDrop con parametri variabili...

Ho trovato il modo di scegliere quali elementi di un documento possono essere resi "dragabili" e quali no:
<script src="funzioni.js"></script>
<script>

var nomi=new Array("uno","immagine");
var offsetX;
var offsetY;
var startX;
var startY;
var dragElement;
var inizializza=function(){
 document.onmousedown=onMouseDown;
 document.onmouseup=onMouseUp; 
}

var onMouseDown=function(e){
 for(n=0;n<nomi.length;n++)
  if(e.target.id==nomi[n]){
   dragElement=e.target;
   offsetX=ExtractNumber(dragElement.style.left);
   offsetY=ExtractNumber(dragElement.style.top);
   startX=e.clientX;
   startY=e.clientY;
   for (n=0;n<document.getElementsByTagName('*').length;n++){
    document.getElementsByTagName('*')[n].style.zIndex=0;
   }
   dragElement.style.zIndex=1;
   document.onmousemove=onMouseMove;
  }
 return false;   
}

var onMouseMove=function(e){
 dragElement.style.left=offsetX+e.clientX-startX;
 dragElement.style.top=offsetY+e.clientY-startY;
}

var onMouseUp=function(){
 document.onmousemove=null;
 dragElement=null; 
}


inizializza();

</script>
<body>

<div id="uno" style="background:red;width:200px;height:100px;position:relative;left:100px;top:50px"></div>

<div id="due" style="background:blue;width:200px;height:100px;position:relative;left:100px;top:150px"></div>
<img id="immagine" src="labirinto.gif" style="position:absolute;width:300px;left:500px;top:250px">
</body>
Funziona... Questo mi permetterebbe di porre il tutto sotto un'unica funzione e chiamarla con una serie variabile di parametri...
Ci provo...

<script src="funzioni.js"></script>
<script>
function DragDrop(){
 var nomi=new Array();
 var offsetX;
 var offsetY;
 var startX;
 var startY;
 var dragElement;
 for(n=0;n<arguments.length;n++)
  nomi[n]=arguments[n];
 
 var inizializza=function(){
  document.onmousedown=onMouseDown;
  document.onmouseup=onMouseUp; 
 }

 var onMouseDown=function(e){
  for(n=0;n<nomi.length;n++)
   if(e.target.id==nomi[n]){
    dragElement=e.target;
    offsetX=ExtractNumber(dragElement.style.left);
    offsetY=ExtractNumber(dragElement.style.top);
    startX=e.clientX;
    startY=e.clientY;
    for (n=0;n<document.getElementsByTagName('*').length;n++){
     document.getElementsByTagName('*')[n].style.zIndex=0;
    }
    dragElement.style.zIndex=1;
    document.onmousemove=onMouseMove;
   }
  return false;   
 }

 var onMouseMove=function(e){
  dragElement.style.left=offsetX+e.clientX-startX;
  dragElement.style.top=offsetY+e.clientY-startY;
 }

 var onMouseUp=function(){
  document.onmousemove=null;
  dragElement=null; 
 }
 inizializza();

}
DragDrop("due","immagine");

</script>
<body>

<div id="uno" style="background:red;width:200px;height:100px;position:relative;left:100px;top:50px"></div>

<div id="due" style="background:blue;width:200px;height:100px;position:relative;left:100px;top:150px"></div>
<img id="immagine" src="labirinto.gif" style="position:absolute;width:300px;left:500px;top:250px">
</body>
Bene!!!

Questo mi potrebbe permettere di "archiviare" questa funzione DragDrop, da richiamare con i nomi degli elementi "dragabili" per parametri...
La inserisco nella mia "libreria" funzioni.js e vediamo se funziona.
Funziona!
Ecco come si presenta il programma adesso con la funzione archiviata:
<script src="funzioni.js"></script>
<script>

DragDrop("uno","immagine");

</script>
<body>

<div id="uno" style="background:red;width:200px;height:100px;position:relative;left:100px;top:50px"></div>

<div id="due" style="background:blue;width:200px;height:100px;position:relative;left:100px;top:150px"></div>
<img id="immagine" src="labirinto.gif" style="position:absolute;width:300px;left:500px;top:250px">
</body>

Drag-drop perfezionato

Ecco. Il Drag-Drop è completo.
Con questo codice, posso "acchiappare" e muovere qualsiasi elemento sulla mia pagina:
<script src="funzioni.js"></script>
<script>


var offsetX;
var offsetY;
var startX;
var startY;
var dragElement;
var inizializza=function(){
 document.onmousedown=onMouseDown;
 document.onmouseup=onMouseUp; 
}

var onMouseDown=function(e){
 
 dragElement=e.target;
 offsetX=ExtractNumber(dragElement.style.left);
 offsetY=ExtractNumber(dragElement.style.top);
 startX=e.clientX;
 startY=e.clientY;
 for (n=0;n<document.getElementsByTagName('*').length;n++){
  document.getElementsByTagName('*')[n].style.zIndex=0;
 }
 dragElement.style.zIndex=1;
 document.onmousemove=onMouseMove;
  
 return false; 
  
}

var onMouseMove=function(e){
 dragElement.style.left=offsetX+e.clientX-startX;
 dragElement.style.top=offsetY+e.clientY-startY;
}

var onMouseUp=function(){
 document.onmousemove=null;
 dragElement=null; 
}


inizializza();

</script>
<body>

<div id="uno" style="background:red;width:200px;height:100px;position:relative;left:100px;top:50px"></div>

<div id="due" style="background:blue;width:200px;height:100px;position:relative;left:100px;top:150px"></div>
<img id="immagine" src="labirinto.gif" style="position:absolute;width:300px;left:500px;top:250px">
</body>
Ho imparato una cosa nuova: il codice document.getElementsByTagName('*') serve per selezionare tutti gli elementi di un documento, al posto di document.all che pare non funzioni sulle vecchie versioni di Firefox.

Con questo codice posso accedere a tutti gli elementi di un documento e trascinarli dove voglio.
La funzione ExtractNumber, che ho creato io e posto in un file js chiamato "funzioni.js" serve per estrarre il numero dalla stringa che esprime le proprietà spaziali di un elemento:
//estrae il valore numerico dalle proprietà di stile
function ExtractNumber(stile){
 numero=Number(stile.replace("px",""));
 return numero;
}

martedì 24 gennaio 2012

Drag-drop con JavaScript

Questa pagina è stata la mia guida per imparare una tecnica per il drag-drop.

Ovviamente, come nel mio stile, l'ho personalizzata un bel po' per cercare di possederne i princìpi anzichè copiarla pedissequamente.
Ecco il risultato personale, almeno per il momento:
<script src="funzioni.js"></script>
<script>
var offsetX;
var startX;
var startY;
var dragElement;
function inizializza(){
 document.onmousedown=onMouseDown;
 document.onmouseup=onMouseUp;
}
function onMouseDown(e){
 dragElement=e.target
 offsetX=ExtractNumber(dragElement.style.left);
 offsetY=ExtractNumber(dragElement.style.top);
 startX=e.clientX;
 startY=e.clientY
 document.onmousemove=onMouseMove;
 return false; 
}

function onMouseMove(e){
 dragElement.style.left=offsetX+e.clientX-startX;
 dragElement.style.top=offsetY+e.clientY-startY;
}

function onMouseUp(){
 document.onmousemove=null;
}
inizializza();
</script>
<body>

<div id="cartello" style="background:red;width:200px;height:100px;position:absolute;left:100px;top:50px"></div>

<div id="ciccio" style="background:blue;width:200px;height:100px;position:absolute;left:100px;top:150px"></div>
</body>
Sembra che funzioni!

Un orologio in JavaScript

Ho messo insieme le mie funzioni per il disegno di linee in una "libreria" chiamata "geometria.js":
function cerchio(spessore,colore,centroX,centroY,raggio){
  var angolo;
  var circonferenza="";
  var puntoX, puntoY
  traccia=function(){
    for(angolo=0;angolo<=360;angolo+=.5){
   puntoX=centroX+raggio*Math.cos(angolo*180/Math.PI)
   puntoY=centroY+raggio*Math.sin(angolo*180/Math.PI)
      circonferenza+="
" } document.body.innerHTML+=circonferenza; } traccia.call(); } function rettaPerPunti(colore,x1,y1,x2,y2){ var linea=""; var lunghezza; function traccia(){ lunghezza=Math.sqrt(Math.pow((x2-x1),2)+Math.pow((y2-y1),2)); angolo=Math.atan((y2-y1)/(x2-x1)); for(var n=0;n<=lunghezza;n++){ linea+="
" } document.body.innerHTML+=linea; } traccia.call(); } function linea(nomeLinea,spessore,colore,orgX,orgY,lunghezza,angolo) { var velAng; var intervallo; var linea=""; var questo=this; this.disegna=function(){ for (var n=0;n<=lunghezza;n++){ linea+="
"; } document.body.innerHTML+=linea; } this.disegna.call(); this.step=function(){ for(var n=0;n<=lunghezza;n++){ document.getElementById(nomeLinea+n).style.left=orgX+(n*Math.cos(angolo*Math.PI/180)); document.getElementById(nomeLinea+n).style.top=orgY+(n*Math.sin(angolo*Math.PI/180)); } angolo+=velAng; } this.ruota=function(velocitaAngolare,tempo){ velAng=velocitaAngolare; setInterval(function(){questo.step()},tempo); } }


Ed ecco un "orologio", che in verità su Firefox risulta piuttosto preciso:
<script src="geometria.js"></script>
<script>

function azione(){
  var miaLinea=new linea("mia",3,"red",300,300,300,-90);
 miaLinea.ruota(6,1000);
 cerchio(3,"blue",300,300,300);
 
  
}
</script>
<body onLoad="azione()">
</body>

Ecco la pagina

La circonferenza perfezionata

<script>
function cerchio(spessore,colore,centroX,centroY,raggio){
 var angolo;
 var punto="";
 
 traccia=function(){
  for(angolo=0;angolo<=360;angolo+=.2){
   punto+="<div style='width:"+spessore+"px;height:"+spessore+"px;background:"+colore+";position:absolute;left:"+(centroX+raggio*Math.cos(angolo*180/Math.PI))+"px;top:"+(centroY+raggio*Math.sin(angolo*180/Math.PI))+"px'></div>"
  }
  document.body.innerHTML+=punto;
 }
 traccia.call();
}

function azione(){
 cerchio(1,"red",400,500,200);
 cerchio(1,"green",200,400,300);
 cerchio(1,"blue",700,400,100);
}
</script>
<body onLoad="azione()">
</body>
Il disegno viene sgranato... Ho in mente un certo artifizio un po' complesso per renderlo più lineare anche in questo caso... e in tutti gli altri.

Ecco la pagina realizzata.

Circonferenza in JavaScript

Ecco una circonferenza:
<script>
function cerchio(){
 var angolo;
 var punto="";
 var raggio=200;
 for(angolo=0;angolo<=360;angolo+=.01){
  punto+="<div style='width:1px;height:1px;background:black;position:absolute;left:"+(300+raggio*Math.cos(angolo*180/Math.PI))+"px;top:"+(300+raggio*Math.sin(angolo*180/Math.PI))+"px'></div>"
 
 }
 document.body.innerHTML+=punto;
}
</script>
<body onLoad="cerchio()">
</body>
Molto facile...

domenica 22 gennaio 2012

Ecco la retta per due punti rappresentata mediante le funzioni trigonometriche

<script>
function rettaPerDuePunti(colore,colPunti,x1,y1,x2,y2){

var linea="";
var lunghezza;
 function punti(){
  document.body.innerHTML+="<div style='width:5px;height:5px;position:absolute;left:"+x1+"px;top:"+y1+"px;background:"+colPunti+"'></div>"
  document.body.innerHTML+="<div style='width:5px;height:5px;position:absolute;left:"+x2+"px;top:"+y2+"px;background:"+colPunti+"'></div>"
  
 }
 function traccia(){
  lunghezza=Math.sqrt(Math.pow((x2-x1),2)+Math.pow((y2-y1),2));
  angolo=Math.atan((y2-y1)/(x2-x1));
  for(var n=0;n<=lunghezza;n++){
   linea+="<div style='position:absolute;width:2px;height:2px;background:"+colore+";left:"+(x1+n*Math.cos(angolo))+"px;top:"+(y1+n*Math.sin(angolo))+"px;'></div>"
   
  }
  document.body.innerHTML+=linea;
 }
 punti.call();
 traccia.call();
}

function azione(){
 rettaPerDuePunti("green","red",100,100,100,300);
 rettaPerDuePunti("blue","red",200,200,500,700);
 rettaPerDuePunti("black","red",100,100,150,500);
 rettaPerDuePunti("red","blue",80,300,300,200);
}
</script>
<body onLoad="azione()">
</body>
...Molto più pulita!

Retta per due punti

Ecco una retta che passa per due punti dati:
<script>
//A(100,100); B(200,300)
var x1=100;
var x2=200;
var y1=100;
var y2=300;
function traccia(){
 document.body.innerHTML+="<div style='position:absolute;background:black;left:"+x1+"px;top:"+y1+"px;width:5px;height:5px;font-size:1px'></div>"
 document.body.innerHTML+="<div style='position:absolute;background:black;left:"+x2+"px;top:"+y2+"px;width:5px;height:5px;font-size:1px'></div>"
 for (x=x1;x<=x2;x++){
  punto="<div style='position:absolute;background:black;left:"+x+"px;top:"+((y2-y1)/(x2-x1)*(x-x1)+y1)+"px;width:1px;height:1px;font-size:1px'></div>"
  document.body.innerHTML+=punto;
 }
}
</script>
<body onLoad="traccia()">
</body>
Concettualmente funziona, ma c'è qualcosa che non mi soddisfa: più le linee sono verticali più risultano "sgranate"...

Forse meglio trovare il modo di far ricorso a metodi trigonometrici...

Una penna ancora molto imperfetta...

Tenendo cliccato il tasto sinistro del mouse e passando sulla pagina, si lascia il segno...
<script>
var punto;
var scrivente="false"

function scrivi(e){
  
 punto="<div style='position:absolute;width:1px;height:1px;font-size:1px;left:"+e.clientX+"px;top:"+e.clientY+"px;background:black'></div>" 
 if(scrivente=="true") document.body.innerHTML+=punto;
}



</script>
<body onMouseDown="javascript:scrivente='true'" onMouseUp="javascript:scrivente='false'" onMouseMove="scrivi(event)">

</body>
Purtroppo se il passaggio del mouse è appena appena un po' veloce molti punti vengono lasciati bianchi. Presumo che sia per i lunghi tempi necessari a fare le "operazioni"...

Linee rotanti anche in Internet Explorer!

Alla grande!

Ho modificato la funzione linea(nomeLinea,spessore,colore,orgX,orgY,lunghezza,ang) posta nella mia "libreria" (non so se la denominazione sia giusta), in modo da usare setInterval in un modo compatibile ai due browsers, con la tecnica del passare come parametro al metodo dell'oggetto che chiama la setInterval, un riferimento all'istanza dell'oggetto.

Il codice per la linea (con in rosso la funzione modificata):
function linea(nomeLinea,spessore,colore,orgX,orgY,lunghezza,ang) {
  var nomeLinea=nomeLinea;
  var orgX=orgX;
  var orgY=orgY;
  var lunghezza=lunghezza;
  var angolo=ang;
  var velAng;
  var intervallo;
  var spessore=spessore;
  var linea="";
 var questo=this;
  this.disegna=function(){
    for (var n=0;n<=lunghezza;n++){
   
        linea+="<div id='"+nomeLinea+n+"' style='font-size:1px;position:absolute;left:"+(orgX+n*Math.cos(angolo*Math.PI/180))+"px;top:"+(orgY+n*Math.sin(angolo*Math.PI/180))+"px;background-color:"+colore+";width:"+spessore+"px;height:"+spessore+"px'></div>"; 
    }
   
    
    document.body.innerHTML+=linea;
  
   }  

  this.disegna.call();
 
  this.step=function(){
     for(var n=0;n<=lunghezza;n++){  
   
        document.getElementById(nomeLinea+n).style.left=orgX+(n*Math.cos(angolo*Math.PI/180));
        document.getElementById(nomeLinea+n).style.top=orgY+(n*Math.sin(angolo*Math.PI/180));
      }
    angolo+=velAng;

   }
  
  this.ruota=function(velocitaAngolare,tempo){ 
     
    velAng=velocitaAngolare;
     setInterval(function(){questo.step()},tempo);
  }
 
}


Il codice della pagina che usa la funzione linea per creare due linee rotanti diverse:
<script src="linea.js">
</script>
<script>
function azione(){
 var uno = new linea("uno",2,"green",300,300,200,45);
 uno.ruota(1,1);
 var due=new linea("due",1,"blue",400,300,200,0);
 due.ruota(-5,1);
}
</script>
<body onLoad="azione()">

</body>
Ed ecco la pagina realizzata

Ecco un setInterval che chiama un metodo di un oggetto! Finalmente il problema sembra risolto!

Ed ecco che ho trovato il modo di far sì che la funzione setInterval faccia riferimento non più all'oggetto window ma all'oggetto oggetto e alla sua istanza. E' banale, ma senza aver chiaro l'ambiente degli scope sembrava insormontabile...

E vediamo se ci riserva altre sorprese...

Intanto ecco qua:
<script>

var oggetto=function(){
 this.funzione=function(){
  var q=this;
  setInterval(function(){document.body.innerHTML+=q},4000);
 }
}
questo=new oggetto();
questo.funzione();
</script>
<body></body>
Ecco l'output:
[object Object][object Object][object Object][object Object][object Object][object Object][object Object][object Object][object Object][object Object][object Object][object Object][object Object][object Object][object Object][object Object][object Object][object Object][object Object][object Object]


Bene, quindi adesso potrei forse far sì che setInterval richiami una funzione dell'oggetto stesso.
Ci provo, e vediamo...

<script>

var oggetto=function(carattere,tempo){
 var carattere=carattere;
 var tempo=tempo;
 var q=this;
 this.funzione=function(){
  
  setInterval(function(){q.chiamata()},tempo);
 }
 this.chiamata=function(){
  window.document.body.innerHTML+=carattere;
 }
}
questo=new oggetto(" fesso ",100);
questo.funzione();
questaltro=new oggetto("<b style='color:red'> SCEMO </b>",500);
questaltro.funzione();
</script>
<body></body>
Funziona! Ho creato due oggetti ognuno dei quali chiama la funzione setInterval con un differente intervallo:
fesso fesso fesso fesso SCEMO fesso fesso fesso fesso fesso SCEMO fesso fesso fesso 


Ecco la pagina realizzata!

Esercizi di scope: capire chi è this per varie funzioni (capito questo, capito moltissimo...)

Una prova con setInterval: faccio in modo che setInterval mi scriva a cosa si riferisce quando dice "this" ed eventuali variabili
<script>
funzione=function(){
 setInterval(function(){document.body.innerHTML+=this},4000);
}

funzione();
</script>
<body></body>
Output:
[object Window][object Window][object Window][object Window]
Per setInterval this corrisponde all'oggetto window.
Ora creo un oggetto questo istanziando un costruttore oggetto.
Nel contesto del costruttore, la funzione funzione evoca setInterval.
<script>

var oggetto=function(){
 this.funzione=function(){
  setInterval(function(){document.body.innerHTML+=this},4000);
 }
}
questo=new oggetto();
questo.funzione();
</script>
<body></body>
Nonostante la funzione setInterval sia evocata da un metodo interno all'oggetto, per lei this si riferisce sempre all'oggetto window.
Piccola variante:
<script>

var oggetto=function(){
 this.funzione=function(){
  alert(this);
  setInterval(function(){document.body.innerHTML+=this},4000);
 }
}
questo=new oggetto();
questo.funzione();
</script>
<body></body>
Ecco: una volta evocata la funzione funzione; metodo dell'oggetto, io le chiedo di dirmi cosa è per lei this, e mi risponde che per lei this è [object Object], quindi la funzione evoca setInterval che dice che per lei invece this è [object Window].

sabato 21 gennaio 2012

Il guaio di setInterval come metodo di window

Ora vediamo cosa c'è che non va in questa sintassi:
<script type="text/javascript">
funz =function(){
 alert(this);
 setInterval("this.funzione()",1000);
}
var oggetto={
 funzione: function(){
  alert("hu");
 },
 
 chiama: function(){
  funz.call(this);
 }
};
oggetto.chiama();


</script>
<body></body>
La funzione si svolge nel contesto dell'oggetto, in quanto il this è [object Object]
In IE ottengo il messaggio di errore: proprietà o metodo non supportato dall'oggetto. Probabilmente si riferisce al metodo setInterval che non è presente nell'oggetto.

Ora non uso il this
<script type="text/javascript">
funz =function(){
 alert(this);
 setInterval("this.funzione()",1000);
}
var oggetto={
 funzione: function(){
  alert("hu");
 },
 
 chiama: function(){
  funz.call();
 }
};
oggetto.chiama();


</script>
<body></body>
L'output è [object Window]. Questo significa che la funzione si svolge nel contesto di window.
Il messaggio di errore è sempre proprietà o metodo non supportato dall'oggetto, che probabilmente si riferisce al metodo this.funzione().
Il problema con setInterval è che dato che questo è un metodo di window viene svolto nello scope di window, e non può vedere i metodi dell'oggetto dall'interno, ma solo dall'esterno.
<script type="text/javascript">
funz =function(){
 alert(this);
 setInterval("oggetto.funzione()",1000);
}
var oggetto={
 funzione: function(){
  alert("hu");
 },
 
 chiama: function(){
  funz.call();
 }
};
oggetto.chiama();


</script>
<body></body>
Così funziona benissimo, perchè la funzione si svolge nello scope di window e vede dall'esterno i metodi dell'oggetto non indirizzati con this ma con il nome dell'oggetto.
Ma quando si abbia a che fare con un costruttore, nel quale bisogna usare necessariamente il this, allora vengono fuori i problemi.

Esercizi grezzi sullo scope...

E va bene.
Cerchiamo di fare esercizi sullo scope...

Quando io scrivo un codice del genere:
<script type="text/javascript">
funz=function(){
 setInterval(this.funzione(),1000);
 
}
var oggetto={
 funzione: function(){
  alert("hu");
 },
 
 chiama: function(){
  funz.call(this);
 }
};
oggetto.chiama();


</script>
<body></body>
la funzione oggetto.chiama mi evoca la funzione funz, che viene portata allo scope dell'oggetto, ossia mediante la call(this) viene fatta rientrare all'interno dell'oggetto e guarda solo ciò che c'è all'interno dell'oggetto... giusto?

Vediamo meglio
<script type="text/javascript">
funz =function(){
 alert(this);
}
var oggetto={
 funzione: function(){
  alert("hu");
 },
 
 chiama: function(){
  funz.call(this);
 }
};
oggetto.chiama();


</script>
<body></body>
 
La funzione oggetto.chiama mi evoca la funzione funz che mi dà come risultato [object Object].
Ora faccio chiamare la medesima funzione dal di fuori di un oggetto.
<script type="text/javascript">
funz =function(){
 alert(this);
}
var oggetto={
 funzione: function(){
  alert("hu");
 },
 
 chiama: function(){
  funz.call(this);
 }
};
funz();


</script>
<body></body>
E ottengo [object Window].

Se la funzione viene chiamata dall'interno dell'oggetto, essa viene portata all'interno dello scope dell'oggetto, mentre se viene chiamata dal di fuori dell'oggetto mantiene lo scope di window.


Ora la chiamo dal di dentro dell'oggetto senza dare il parametro this alla call:
<script type="text/javascript">
funz =function(){
 alert(this);
}
var oggetto={
 funzione: function(){
  alert("hu");
 },
 
 chiama: function(){
  funz.call();
 }
};
oggetto.chiama();


</script>
<body></body>
ottengo come risultato [object Window].
Ora faccio che la funzione esterna venga chiamata dall'oggetto ed evochi un altro metodo dell' oggetto, con le due modalità di call
<script type="text/javascript">
funz =function(){
 this.funzione();
}
var oggetto={
 funzione: function(){
  alert("hu");
 },
 
 chiama: function(){
  funz.call(this);
 }
};
oggetto.chiama();


</script>
<body></body>
Output: hu: esegue l'altro metodo dell'oggetto.

<script type="text/javascript">
funz =function(){
 this.funzione();
}
var oggetto={
 funzione: function(){
  alert("hu");
 },
 
 chiama: function(){
  funz.call();
 }
};
oggetto.chiama();


</script>
<body></body>
Output: errore: Proprietà o metodo non supportati dall'oggetto, in corrispondenza di this.funzione().
Perchè?

Aggiungiamo una riga che mostri il contesto in cui le funzioni agiscono.

Ricominciamo:
<script type="text/javascript">
funz =function(){
 alert(this);
 this.funzione();
}
var oggetto={
 funzione: function(){
  alert("hu");
 },
 
 chiama: function(){
  funz.call(this);
 }
};
oggetto.chiama();


</script>
<body></body>
Output: 1) [object Object], 2) hu Questo significa che il contesto in cui la funzione si trova è quello dell'oggetto.

<script type="text/javascript">
funz =function(){
 alert(this);
 this.funzione();
}
var oggetto={
 funzione: function(){
  alert("hu");
 },
 
 chiama: function(){
  funz.call();
 }
};
oggetto.chiama();


</script>
<body></body>
Output: [object Window]... poi più niente. Vado con l'IDE a vedere dove sta l'errore, se ce n'è uno...
Bene: in corrispondenza di this.funzione() risulta proprietà o metodo non supportati dall'oggetto.
Con il this la funzione esterna viene portata nello scope dell'oggetto, mentre senza resta nello scope di window.

Funzioni-"prostituta" senza il call...

Proseguiamo seguendo pedissequamente gli esempi del corso online.
<script type="text/javascript">
 
var stampaNome = function() {
  alert(this.nome || "Non ho nessun nome");
}
 
var persona = {
  nome: "Alberto",
  stampaNome: stampaNome
}
 
var animale = {
  razza: "Pastore tedesco",
  stampaNome: stampaNome
}
 
persona.stampaNome();
animale.stampaNome();
 
</script> 
Qui mi scontro con una novità: quel ||.
Proviamo ad eliminarlo.
<script type="text/javascript">
 
var stampaNome = function() {
  alert(this.nome);
}
 
var persona = {
  nome: "Alberto",
  stampaNome: stampaNome
}
 
var animale = {
  razza: "Pastore tedesco",
  stampaNome: stampaNome
}
 
persona.stampaNome();
animale.stampaNome();
 
</script> 
Nel primo caso gli output sono Alberto e non ho nessun nome.
Nel secondo sono Alberto e undefined.
Quell'operatore di "o", ||, permette di dare una risposta alternativa all'undefined.

Appurato questo, e imparata una nuova tecnica, analizziamo lo scope.

Una funzione può essere condivisa da più oggetti e "calarsi" nello scope di ognuno.

Vediamo meglio personalizzando:
<script type="text/javascript">
 
var stampaNome = function() {
   alert(this.nome);
}
 
var persona = {
   nome: "Alberto",
   stampaNome: stampaNome
}
 
var animale = {
 nome: "Rex",
   razza: "Pastore tedesco",
   stampaNome: stampaNome
}
 
persona.stampaNome();
animale.stampaNome();
 
</script> 
Output: Alberto e Rex.

Che differenza c'è fra il condividere una funzione così e l'uso del call?

Esercizi sullo scope

Questo codice, liberamente personalizzato dal codice di questa pagina è esplicativo:
<script>
function funzioneGlobale(){
 alert(this);
}

var oggetto = {
 funzioneLocale: function(){
  alert(this);
 }
}

funzioneGlobale();
oggetto.funzioneLocale();
</script>
La parola this, in realtà, indica semplicemente lo scope di una funzione.

Nel primo caso, essendo una funzione globale, l'output è [object Window], mentre nel secondo, essendo una funzione locale dell'oggetto oggetto, l'output è [object Object].
E' molto importante tenere a mente il concetto semplice ma fondamentale che this indica lo scope
Ora cominciamo a distorcere, straziare, torturare quel codice per farci un po' di esperimenti...

Chiamiamo la funzione globale da quella locale:
<script>
function funzioneGlobale(){
 alert(this);
}

var oggetto = {
 funzioneLocale: function(){
  funzioneGlobale();
 }
}

oggetto.funzioneLocale();
</script>
Output: [object Window]
La funzione globale viene chiamata dalla funzione locale.
Chiamiamo la funzione locale da quella globale:
<script>
function funzioneGlobale(){
 oggetto.funzioneLocale();
}

var oggetto = {
 funzioneLocale: function(){
  alert(this);
 }
}

funzioneGlobale();
</script>
Output: [object Object]
La funzione locale viene chiamata dalla funzione globale.
In conclusione: Ogni funzione dichiara lo scope nel quale viene eseguita.

venerdì 20 gennaio 2012

Lo scope delle "funzioni-prostituta"

Ora vediamo come si comportano le "funzioni-prostituta", quelle che vengono chiamate con call. Vediamo se una di queste funzioni esterne si comporta come una funzione interna per quanto riguarda lo scope.
Facciamo accedere una funzione esterna a una variabile pubblica dell'oggetto.
<script>

function oggetto(nome, cognome){
 this.nome=nome;
 this.cognome=cognome;  
}

function scrivi(){
 alert(this.nome+" "+this.cognome);
}

function azione(){
 Mario=new oggetto("Mario", "Rossi");
 scrivi.call(Mario);
}
</script>
<body onLoad="azione();">
</body>
Output: "Mario Rossi".
Conclusione: una funzione esterna usata con il call può leggere le variabili pubbliche di un oggetto.
Proviamo con le variabili private:
<script>

function oggetto(nome, cognome){
 var nome=nome;
 var cognome=cognome;  
}

function scrivi(){
 alert(this.nome+" "+this.cognome);
}

function azione(){
 Mario=new oggetto("Mario", "Rossi");
 scrivi.call(Mario);
}
</script>
<body onLoad="azione();">
</body>
Output: "undefined undefined".

Se poi elimino il this dalla funzione esterna...
<script>

function oggetto(nome, cognome){
 var nome=nome;
 var cognome=cognome;  
}

function scrivi(){
 alert(nome+" "+cognome);
}

function azione(){
 Mario=new oggetto("Mario", "Rossi");
 scrivi.call(Mario);
}
</script>
<body onLoad="azione();">
</body>
ottengo una pagina completamente bianca e un errore: nome non è definito.
Conclusione: una funzione chiamata con il call non può leggere le variabili private. Dunque ha uno scope pubblico.
Questo è meno lapalissiano...

Continuano gli esercizi di scope (il trionfo di La Palisse!)

Ora il mio problema è che voglio che una funzione esterna all'oggetto chiami una funzione interna...

Procediamo con ordine...

Una funzione pubblica (metodo) di un oggetto ne chiama un'altra pubblica.
<script>

function oggetto(nome, cognome){
 var nome=nome;
 var cognome=cognome;
 this.scrivi = function(){
  alert(nome+" "+cognome);
 }
 this.chiamaScrivi=function(){
  this.scrivi();
 }
}

function azione(){
 Mario=new oggetto("Mario", "Rossi");
 Mario.chiamaScrivi();
}
</script>
<body onLoad="azione();">
</body>
Output: "Mario Rossi".
Conclusione: una funzione dell'oggetto può chiamare (lapalissianamente) una funzione pubblica dello stesso oggetto
Una funzione esterna chiama una funzione pubblica di un oggetto:
<script>

function oggetto(nome, cognome){
 var nome=nome;
 var cognome=cognome;
 this.scrivi = function(){
  alert(nome+" "+cognome);
 }
 this.chiamaScrivi=function(){
  this.scrivi();
 }
}

function azione(){
 Mario=new oggetto("Mario", "Rossi");
 Mario.scrivi();
}
</script>
<body onLoad="azione();">
</body>
(che poi è la stessa cosa di prima)
Output: "Mario Rossi". Conclusione: una funzione esterna può chiamare (ancora lapalissianamente) una funzione pubblica di un oggetto.
Una funzione interna all'oggetto ne chiama una privata dello stesso oggetto:
<script>

function oggetto(nome, cognome){
 var nome=nome;
 var cognome=cognome;
 var scrivi = function(){
  alert(nome+" "+cognome);
 }
 this.chiamaScrivi=function(){
  scrivi();
 }
}

function azione(){
 Mario=new oggetto("Mario", "Rossi");
 Mario.chiamaScrivi();
}
</script>
<body onLoad="azione();">
</body>
Output: "Mario Rossi".
Conclusione: un metodo può chiamare un metodo privato all'interno di un oggetto
Una funzione esterna all'oggetto chiama una funzione privata dell'oggetto.
<script>

function oggetto(nome, cognome){
 var nome=nome;
 var cognome=cognome;
 var scrivi = function(){
  alert(nome+" "+cognome);
 }
 this.chiamaScrivi=function(){
  scrivi();
 }
}

function azione(){
 Mario=new oggetto("Mario", "Rossi");
 Mario.scrivi();
}
</script>
<body onLoad="azione();">
</body>
Bene: ottengo una pagina bianca senza spiegazioni!
In Internet Explorer ottengo un errore del tipo Proprietà o metodo non supportati dall'oggetto.
Conclusione: una funzione esterna non può chiamare un metodo privato di un oggetto

Tutto tremendamente lapalissiano...

Esercizi di scope

Ho un costruttore oggetto.

Il metodo scrivi appartiene a questo oggetto.
Agisce da dentro questo oggetto.
Ora gli faccio leggere delle variabili pubbliche dell'oggetto e poi delle variabili private.

Variabili pubbliche:
<script>

function oggetto(nome, cognome){
 this.nome=nome;
 this.cognome=cognome;
 this.scrivi = function(){
  alert(nome+" "+cognome);
 }
}

function azione(){
 Mario=new oggetto("Mario", "Rossi");
 Mario.scrivi();
}
</script>
<body onLoad="azione();">
</body>
Ho stabilito la convenzione di marcare le variabili pubbliche in verde.
L'output è una casella di avviso con scritto "Mario Rossi".
Conclusione: il metodo legge le variabili pubbliche dello stesso oggetto(è lapalissiano).
Ora leggo le variabili pubbliche da una funzione esterna all'oggetto:
<script>

function oggetto(nome, cognome){
 this.nome=nome;
 this.cognome=cognome;
 this.scrivi = function(){
  alert(nome+" "+cognome);
 }
}

function azione(){
 Mario=new oggetto("Mario", "Rossi");
 alert(Mario.nome+" "+Mario.cognome);
}
</script>
<body onLoad="azione();">
</body>
Output: "Mario Rossi".
Conclusione: la funzione esterna legge le variabili pubbliche di un oggetto.
Ora ripeto l'esperimento con variabili private (che per convenzione segno in rosso)
<script>

function oggetto(nome, cognome){
 var nome=nome;
 var cognome=cognome;
 this.scrivi = function(){
  alert(nome+" "+cognome);
 }
}

function azione(){
 Mario=new oggetto("Mario", "Rossi");
 Mario.scrivi();
}
</script>
<body onLoad="azione();">
</body>
Output: "Mario Rossi".
Conclusione: il metodo legge le variabili private dello stesso oggetto..
Ora cerco di leggere le variabili private da una funzione esterna:
<script>

function oggetto(nome, cognome){
 var nome=nome;
 var cognome=cognome;
 this.scrivi = function(){
  alert(nome+" "+cognome);
 }
}

function azione(){
 Mario=new oggetto("Mario", "Rossi");
 alert(Mario.nome+" "+Mario.cognome);
}
</script>
<body onLoad="azione();">
</body>
Output: "undefined undefined". Conclusione: la funzione esterna non legge le variabili private di un oggetto.

Tutto lapalissiano, del resto, ma è bene allenarsi!

Le funzioni-prostituta

Ecco.
Due istanze dello stesso oggetto possono condividere una funzione scritta esternamente al costruttore dell'oggetto.
Ecco:
<script>

function uomo(n){
 this.nome=n;
 scrivi.call(this);
}

function scrivi(){
 alert(this.nome);
}
function azione(){
 mario=new uomo("Mario");
 giovanni=new uomo("Giovanni"); 
}
</script>
<body onLoad="azione();">
</body>
Ecco in rosso la funzione-prostituta, che chiamo molto poeticamente in questo modo perchè "va con tutti".

Per chiamarla, viene passato come parametro il this. Anche se la funzione non prevede parametri.

Il metodo per chiamarla è call

Abbandoniamo la sintassi document.write per usare il document.body.innerHTML

Con il document.write vengono fuori un sacco di problemi. Per cominciare, ciò che è già presente nella pagina sparisce, e poi la pagina non smette più di caricarsi.
Ho fatto qualche ricerca e ho appreso da una pagina web che si può usare anche la sintassi document.body.innerHTML, con gli stessi risultati... e sempre con la stessa mancanza di risultato in Internet Explorer... GRUNTH!
function linea(nomeLinea,spessore,colore,orgX,orgY,lunghezza,ang){
 var nomeLinea=nomeLinea;
 var orgX=orgX;
 var orgY=orgY;
 var lunghezza=lunghezza;
 var angolo=ang;
 var velAng;
 var intervallo;
 var spessore=spessore;
 var linea="";
 this.disegna=function(){
  for (var n=0;n<=lunghezza;n++){
   
     linea+="<div id='"+nomeLinea+n+"' style='font-size:1px;position:absolute;left:"+(orgX+n*Math.cos(angolo*Math.PI/180))+"px;top:"+(orgY+n*Math.sin(angolo*Math.PI/180))+"px;background-color:"+colore+";width:"+spessore+"px;height:"+spessore+"px'></div>"; 
  
   
  }
  document.body.innerHTML+=linea;
  
  }  
 this.disegna.call();
 
 this.step=function(){
   for(var n=0;n<=lunghezza;n++){  
     document.getElementById(nomeLinea+n).style.left=orgX+n*Math.cos(angolo*Math.PI/180);
     document.getElementById(nomeLinea+n).style.top=orgY+n*Math.sin(angolo*Math.PI/180);
    }
  angolo+=velAng;

  }
  
 this.ruota=function(velocitaAngolare,tempo){ 
   window.clearInterval(intervallo);
  velAng=velocitaAngolare;
   intervallo=window.setInterval(function(linea) {linea.step()},tempo,this);
 }
 
}
E così riesco ad eseguire questo:
<script type="text/javascript" src="linea.js"></script>
<script>
var prima;
function traccia(){
 prima=new linea("uno",2,"green",100,100,300,45);
 prima.ruota(1,1);
}
</script>
<body onLoad="traccia()">
<div>Ciao fesso</div>

</body>
che prima anche in Firefox non funzionava. Funziona, come al solito, in Firefox ma non in IE.

Dovrò decidermi prima o poi a imparare la lingua di IE...

Un tripudio di linee colorate rotanti!!!

Fantastico!

Ecco come, con l'uso del mio oggettino linea, si possono costruire tutte le linee che si vogliono, ognuna con la propria velocità di rotazione e anche con il proprio verso, che per rendere negativo basta impostare il parametro "velocità angolare" del metodo ruota con un valore negativo:
<script>

function linea(nomeLinea,spessore,colore,orgX,orgY,lunghezza,ang){
 var nomeLinea=nomeLinea;
 var orgX=orgX;
 var orgY=orgY;
 var lunghezza=lunghezza;
 var angolo=ang;
 var velAng;
 var intervallo;
 var spessore=spessore;
 this.disegna=function(){
  for (var n=0;n<=lunghezza;n++)
  document.write("<div id='"+nomeLinea+n+"' style='font-size:1px;position:absolute;left:"+(orgX+n*Math.cos(angolo*Math.PI/180))+"px;top:"+(orgY+n*Math.sin(angolo*Math.PI/180))+"px;background-color:"+colore+";width:"+spessore+"px;height:"+spessore+"px'></div>"); 
  }  
 this.disegna.call();

 this.step=function(){
   for(var n=0;n<=lunghezza;n++){  
     document.getElementById(nomeLinea+n).style.left=orgX+n*Math.cos(angolo*Math.PI/180);
     document.getElementById(nomeLinea+n).style.top=orgY+n*Math.sin(angolo*Math.PI/180);
    }
  angolo+=velAng;

  }
  
 this.ruota=function(velocitaAngolare,tempo){ 
   clearInterval(intervallo);
  velAng=velocitaAngolare;
   intervallo=window.setInterval(function(linea) {linea.step()},tempo,this);
 }
 
}

prima=new linea("prima",1,"red",500,300,300,45);
prima.ruota(2,1);

seconda=new linea("seconda",2,"green",500,500,300,0);
seconda.ruota(5,1);

terza=new linea("terza",3,"blue",700,300,400,90);
terza.ruota(-2,1);

</script>

<body>

</body>

Una linea rotante completa!

Ecco una linea che ruota. Ho inserito i metodi step e ruota.
<script>

function linea(nomeLinea,spessore,colore,orgX,orgY,lunghezza,ang){
 var nomeLinea=nomeLinea;
 var orgX=orgX;
 var orgY=orgY;
 var lunghezza=lunghezza;
 var angolo=ang;
 var velAng;
 var intervallo;
 var spessore=spessore;
 this.disegna=function(){
  for (var n=0;n<=lunghezza;n++)
  document.write("<div id='"+nomeLinea+n+"' style='font-size:1px;position:absolute;left:"+(orgX+n*Math.cos(angolo*Math.PI/180))+"px;top:"+(orgY+n*Math.sin(angolo*Math.PI/180))+"px;background-color:"+colore+";width:"+spessore+"px;height:"+spessore+"px'></div>"); 
  }  
 this.disegna.call();

 this.step=function(){
   for(var n=0;n<=lunghezza;n++){  
     document.getElementById(nomeLinea+n).style.left=orgX+n*Math.cos(angolo*Math.PI/180);
     document.getElementById(nomeLinea+n).style.top=orgY+n*Math.sin(angolo*Math.PI/180);
    }
  angolo+=velAng;

  }
  
 this.ruota=function(velocitaAngolare,tempo){ 
   clearInterval(intervallo);
  velAng=velocitaAngolare;
   intervallo=window.setInterval(function(linea) {linea.step()},tempo,this);
 }
 
}

prima=new linea("prima",2,"black",500,300,300,45);
prima.ruota(1,10);



</script>

<body>

</body>


Per tracciare una linea bisogna fornire come parametri:
  1. Il nome della linea;
  2. lo spessore della linea;
  3. il colore della linea;
  4. la coordinata X del punto di origine;
  5. la coordinata Y del punto di origine;
  6. la lunghezza della linea;
  7. l'angolo di inclinazione della linea.


Per far ruotare la linea bisogna evocare il metodo ruota fornendo come parametri:
  1. la velocità angolare del movimento (termine improprio: in realtà sarebbe l'angolo percorso a ogni intervallo)
  2. il tempo fra due spostamenti (ossia la durata dell'intervallo in millisecondi)

Costruzione dell'oggetto linea e scoperta di call() per eseguire un metodo

Creiamo una buona volta questo oggetto linea.

Eccolo.
Ho scoperto anche il metodo call() che mi permette di innescare un metodo dell'oggetto subito, in fase di istanziazione.
<script>

function linea(colore,orgX,orgY,lunghezza,angolo){
 var orgX=orgX;
 var orgY=orgY;
 var lunghezza=lunghezza;
 var angolo=angolo;
 this.disegna=function(){
  for (var n=0;n<=lunghezza;n++)
  document.write("<div id='uno"+n+"' style='font-size:1px;position:absolute;left:"+(orgX+n*Math.cos(angolo*Math.PI/180))+"px;top:"+(orgY+n*Math.sin(angolo*Math.PI/180))+"px;background-color:"+colore+";width:3px;height:3px'></div>"); 
  }  
 this.disegna.call();
}

lineaUno=new linea("red",200,300,500,45);
lineaDue=new linea("green",400,100,600,100);
lineaTre=new linea("blue",500,300,300,200);
</script>

<body>

</body>

giovedì 19 gennaio 2012

Un cartellino che segue il mouse

Un cartellino stupido che segue il mouse.
Sparisce se il mouse va fuori dalla finestra.
<script>
function segna(e){

 document.getElementById("coords").style.left=e.clientX+10;
 document.getElementById("coords").style.top=e.clientY+10;
 document.getElementById("coords").style.visibility="visible";
}
 
function occulta(){
 document.getElementById("coords").style.visibility="hidden";
}
</script>

<body onMouseMove="segna(event);" onMouseOut="occulta()">
<div id="coords" style="visibility:hidden;padding:10px;background:yellow;border:2px solid green;position:absolute;width:110px;height:30px;">Io seguo il mouse</div>
</body>

Ecco una linea rotante al centro della pagina.

Ecco. Ho dovuto mettere le variabili non più come parametri della funzione linea ma come variabili, in quanto devono essere condivise fra due funzioni.
Ovviamente, la cosa è rimediabile semplicemente creando una classe linea, il cui costruttore prevede l'inserimento delle suddette variabili come parametri, e un metodo per tracciarla insieme a uno per muoverla.
<script>
var angolo=45;
var lunghezza=300
var orgX=500;
var orgY=400;
function linea(){
 for (var n=0;n<=lunghezza;n++){
  document.write("<div id='uno"+n+"' style='font-size:1px;position:absolute;left:"+(orgX+n*Math.cos(angolo*Math.PI/180))+"px;top:"+(orgY+n*Math.sin(angolo*Math.PI/180))+"px;background-color:blue;width:3px;height:3px'></div>"); 
 }  
}





var intervallo;
function step(){
 for(var n=0;n<=lunghezza;n++){  
  document.getElementById("uno"+n).style.left=orgX+n*Math.cos(angolo*Math.PI/180);
  document.getElementById("uno"+n).style.top=orgY+n*Math.sin(angolo*Math.PI/180);
  
 }
 angolo+=1;

}
function muovi(){ 
 clearInterval(intervallo);
 intervallo=setInterval(function() {step()},1);
}
 
linea();

</script>

<body onClick="muovi();">

</body>

La linea si svincola dall'origine

Fornendo come parametri della funzione linea anche le coordinate del punto di origine, posso tracciare le linee dove mi pare e non più necessariamente a partire dal punto (0,0).
<script>
function linea(orgX,orgY,lunghezza,angolo){
 for (var n=0;n<=lunghezza;n++){
  document.write("<div id='uno"+n+"' style='font-size:1px;position:absolute;left:"+(orgX+n*Math.cos(angolo*Math.PI/180))+"px;top:"+(orgY+n*Math.sin(angolo*Math.PI/180))+"px;background-color:blue;width:1px;height:1px'></div>"); 
 }  
}


 
linea(100,200,500,60);
linea(100,100,300,30);
</script>

Una funzione più seria per tracciare linee

Ecco un modo nuovo e più "corretto" di codificare il disegno di una linea.
Non più specificando l'inizio e la fine sull'asse delle x, ma specificando la lunghezza della linea e l'angolo, in gradi, della sua inclinazione.
La lunghezza e l'angolo vengono forniti alla funzione che traccia la linea come parametri, le coordinate di ogni punto vengono stabilite mediante funzioni trigonometriche:
<script>
function linea(lunghezza,angolo){
 for (var n=0;n<=lunghezza;n++){
  document.write("<div id='uno"+n+"' style='font-size:1px;position:absolute;left:"+n*Math.cos(angolo*Math.PI/180)+"px;top:"+n*Math.sin(angolo*Math.PI/180)+"px;background-color:blue;width:1px;height:1px'></div>"); 
 }  
}

 
linea(500,60);
linea(300,45);
linea(800,30);
linea(600,85);
</script>
Funziona perfettamente.

Un rudimentale giochino di trigonometria... e la linea gira!

<script>
function popola(){
 for (var n=0;n<=300;n++){
  document.write("<div id='uno"+n+"' style='font-size:1px;position:absolute;left:"+n+"px;top:"+n+"px;background-color:blue;width:5px;height:5px'></div>");
  
 }
  
}
var ang=0;
var intervallo;
function step(){
 for(var n=00;n<=300;n++){
  var g=(ang*Math.PI/180);
  var sinistra=Number((document.getElementById("uno"+n).style.left).replace("px",""));
  var alto=Number((document.getElementById("uno"+n).style.top).replace("px",""));
  sinistra=n*Math.cos(g);
  alto=n*Math.sin(g);
  document.getElementById("uno"+n).style.left=sinistra;
  document.getElementById("uno"+n).style.top=alto;
  
 }
 ang+=1;

}
function muovi(){ 
 clearInterval(intervallo);
 intervallo=setInterval(function() {step()},10);
}
 
popola();
</script>

<body onClick="muovi();">

</body>
...qualche difficoltà con gradi e radianti presto superata!

mercoledì 18 gennaio 2012

La mia prima linea animata

Ecco il mio primo tentativo di animare una linea:
<script>
function popola(){
 for (var n=1;n<=300;n++){
  document.write("<div id='uno"+n+"' style='position:absolute;left:"+n+"px;top:"+n+"px;background-color:blue;width:2px;height:2px'></div>");
  
 }
  
}
var coefficiente=1;
var intervallo;
function step(){
 for(var n=1;n<=300;n++){
  var sinistra=Number((document.getElementById("uno"+n).style.left).replace("px",""));
  var alto=Number((document.getElementById("uno"+n).style.top).replace("px",""));
  
  alto=coefficiente*sinistra;
  document.getElementById("uno"+n).style.left=sinistra;
  document.getElementById("uno"+n).style.top=alto;
  
 }
 coefficiente+=.005;
}
function muovi(){ 
 clearInterval(intervallo);
 intervallo=setInterval(function() {step()},1);
}
 
popola();
</script>

<body onClick="muovi();">

</body>
Sarebbe molto meglio che la linea mantenesse la sua lunghezza mentre si muove.
Per questo, mi sarà necessario rispolverare un po' di trigonometria...
BLEAH!!!
In Internet Explorer è una linea grossolana che si muove lenta lenta.
Cerco di fare qualche aggiustamento...
<script>
function popola(){
 for (var n=1;n<=300;n++){
  document.write("<div id='uno"+n+"' style='font-size:1px;position:absolute;left:"+n+"px;top:"+n+"px;background-color:blue;width:2px;height:2px'></div>");
  
 }
  
}
var coefficiente=1;
var intervallo;
function step(){
 for(var n=1;n<=300;n++){
  var sinistra=Number((document.getElementById("uno"+n).style.left).replace("px",""));
  var alto=Number((document.getElementById("uno"+n).style.top).replace("px",""));
  
  alto=coefficiente*sinistra;
  document.getElementById("uno"+n).style.left=sinistra;
  document.getElementById("uno"+n).style.top=alto;
  
 }
 coefficiente+=.05;
}
function muovi(){ 
 clearInterval(intervallo);
 intervallo=setInterval(function() {step()},1);
}
 
popola();
</script>

<body onClick="muovi();">

</body>
Ho dovuto accelerare il movimento e impostare lo stile font-size a 1 perchè il DIV in Explorer tiene conto anche della grandezza dei caratteri, diversamente da Firefox. Comunque in Explorer si muove più "a scatti"... forse imparerò a usare anche quel browser come si deve, prima o poi...

Primo tentativo rudimentale di muovere una linea disegnata mediante javaScript

Torno alle linee.
Dato che, a quanto pare, il DIV non supporta l'attributo name, ho trovato il modo di identificare un DIV come appartenente a una curva, assegnando il nome della curva seguito da un numero progressivo per formare l'ID di ciascun punto della curva.
<script>
function popola(){
 for (var n=1;n<=300;n++){
  document.write("<div id='uno"+n+"' style='position:absolute;left:"+n+"px;top:"+n+"px;background-color:blue;width:1px;height:1px'></div>");
  
 }
  
}
function muovi(){
 for(var n=1;n<=300;n++){
  var sinistra=Number((document.getElementById("uno"+n).style.left).replace("px",""));
  sinistra+=100;
  document.getElementById("uno"+n).style.left=sinistra;
 }
}
popola();
</script>

<body onClick="muovi();">

</body>
A ogni click sul corpo del documento la linea si sposta a destra.

Overloading dei coriandoli... e delle funzioni!

Ora mi trovo davanti un oggetto che ha i metodi step() e muovi().
Che ne faccio?

Il metodo step() ha bisogno di diversi parametri
this.step=function(intX,intY,limX,limY){
...che sono necessari nel momento in cui io voglia far rimbalzare l'oggetto contro un limite.
I parametri intX e intY sono sempre necessari in quanto misurano la lunghezza di un passo, mentre i parametri limX e limY sono superflui quando non voglio far rimbalzare l'oggetto.
Allora posso ricorrere all'overloading, creando due metodi step, uno con i limiti e uno senza.
Credo che questa tecnica sia usabile in JavaScript.
Proviamo.
Questo è l'oggetto oggetto:
function oggetto(nome){
  var MioNome=nome;
 
 var Sinistra=Number((document.getElementById(MioNome).style.left).replace("px",""));
 var Alto=Number((document.getElementById(MioNome).style.top).replace("px",""));
 var Larghezza=Number((document.getElementById(MioNome).style.width).replace("px",""));
 var Altezza=Number((document.getElementById(MioNome).style.height).replace("px",""));
 var Intervallo;
 var dirX="destra", dirY="basso"
  this.step=function(intX,intY,limX,limY){
  
  if(Sinistra>limX)
   dirX="sinistra";
  if(Sinistra<0)
   dirX="destra" 
  if(dirX=="sinistra")
   intX=-intX;
  if(dirX=="destra")
   intX=intX;

  if(Alto>limY)
   dirY="alto";
  if(Alto<0)
   dirY="basso" 
  if(dirY=="alto")
   intY=-intY;
  if(dirX=="basso")
   intY=intY;

    Sinistra+=intX
  Alto+=intY
    document.getElementById(MioNome).style.left=Sinistra;
  document.getElementById(MioNome).style.top=Alto;
  }
 
 this.muovi=function(tempo, intX, intY, limX, limY){
  clearInterval(Intervallo);
  Intervallo=window.setInterval(function(oggetto){oggetto.step(intX, intY, limX, limY)},tempo,this);
 }
 this.inter=function(){
  clearInterval(Intervallo);
 }
  
}
Posso creare un'altra funzione step con i soli parametri relativi alla lunghezza del passo.
E ci vuole un'altra funzione muovi che chiami questa funzione anzichè quella con i limiti.

Ci provo.

function oggetto(nome){
  var MioNome=nome;
 
 var Sinistra=Number((document.getElementById(MioNome).style.left).replace("px",""));
 var Alto=Number((document.getElementById(MioNome).style.top).replace("px",""));
 var Larghezza=Number((document.getElementById(MioNome).style.width).replace("px",""));
 var Altezza=Number((document.getElementById(MioNome).style.height).replace("px",""));
 var Intervallo;
 var dirX="destra", dirY="basso"
  this.step=function(intX,intY,limX,limY){
  
  if(Sinistra>limX)
   dirX="sinistra";
  if(Sinistra<0)
   dirX="destra" 
  if(dirX=="sinistra")
   intX=-intX;
  if(dirX=="destra")
   intX=intX;

  if(Alto>limY)
   dirY="alto";
  if(Alto<0)
   dirY="basso" 
  if(dirY=="alto")
   intY=-intY;
  if(dirX=="basso")
   intY=intY;

    Sinistra+=intX
  Alto+=intY
    document.getElementById(MioNome).style.left=Sinistra;
  document.getElementById(MioNome).style.top=Alto;
  }
 
 this.step=function(intX,intY){
  
    Sinistra+=intX
  Alto+=intY
    document.getElementById(MioNome).style.left=Sinistra;
  document.getElementById(MioNome).style.top=Alto;
  }

 this.muovi=function(tempo, intX, intY, limX, limY){
  clearInterval(Intervallo);
  Intervallo=window.setInterval(function(oggetto){oggetto.step(intX, intY, limX, limY)},tempo,this);
 }

 this.muovi=function(tempo, intX, intY){
  clearInterval(Intervallo);
  Intervallo=window.setInterval(function(oggetto){oggetto.step(intX, intY)},tempo,this);
 }
 
 this.inter=function(){
  clearInterval(Intervallo);
 }
  
}
Ora uso i miei coriandoli con queste nuove funzioni...

Benissimo! Partono imperterriti e se ne vanno all'infinito! Segno che è stata usata la funzione muovi(tempo, intX, intY) anzichè la funzione muovi(tempo, intX, intY, limX, limY).

ù Ed ecco l'overloading realizzato!

martedì 17 gennaio 2012

Coriandoli in Firefox

<script src="oggetto.js"></script>
<script>


function crea(){
  for(var n=0;n<document.getElementsByTagName("div").length;n++)
   {
    var DivId=document.getElementsByTagName("div")[n].id;
    window[DivId] = new oggetto(DivId);
   }
 
}


function clic(e){
  window[e.currentTarget.id].muovi(1,1,1,800,700);
}

function over(e){
 window[e.currentTarget.id].inter();
}

</script>

<body onLoad="crea();" bgcolor=black>
<div id="uno" style="position:absolute;left:0px;top:0px;width:10px;height:10px;background:blue" onClick="clic(event)"></div>
<div id="due" style="position:absolute;left:0px;top:50px;width:10px;height:10px;background:green" onClick="clic(event)"></div>
<div id="tre" style="position:absolute;left:0px;top:100px;width:10px;height:10px;background:yellow" onClick="clic(event)"></div>
<div id="quattro" style="position:absolute;left:0px;top:150px;width:10px;height:10px;background:red" onClick="clic(event)"></div>
<div id="cinque" style="position:absolute;left:0px;top:200px;width:10px;height:10px;background:cyan" onClick="clic(event)"></div>
<div id="sei" style="position:absolute;left:0px;top:250px;width:10px;height:10px;background:#AAFFAA" onClick="clic(event)"></div>
</body>
Cliccando su un coriandolo alla volta, questo si mette in movimento!

Stipiamo l'oggetto

Ho stipato l'oggetto in un file .js e lo richiamo nel codice.
Funziona.
<script src="oggetto.js"></script>
<script>


function crea(){
  for(var n=0;n<document.getElementsByTagName("img").length;n++)
   {
    var DivId=document.getElementsByTagName("img")[n].id;
    window[DivId] = new oggetto(DivId);
   }
 
}


function clic(e){
  window[e.currentTarget.id].muovi(1,1,1,500,700);
}

function over(e){
 window[e.currentTarget.id].inter();
}
</script>

<body onLoad="crea();">
<img id="ciccio" style="width:50px;height:50px;position:absolute;top:0px" src="pallone.gif" onClick="clic(event)" onMouseOver="over(event)">
<img id="pippo" style="width:50px;height:50px;position:absolute;top:100px" src="pallone.gif" onClick="clic(event)" onMouseOver="over(event)">
<img id="mimmo" style="width:50px;height:50px;position:absolute;top:200px" src="pallone.gif" onClick="clic(event)" onMouseOver="over(event)">
</body>

Aggiunta di argomenti ai metodi: i limiti dello spazio di movimento come parametri esterni all'oggetto.

Ecco forniti come parametri esterni anche i limiti del campo in cui rimbalzano le palle!
<script>
function oggetto(nome){
  var MioNome=nome;
 
 var Sinistra=Number((document.getElementById(MioNome).style.left).replace("px",""));
 var Alto=Number((document.getElementById(MioNome).style.top).replace("px",""));
 var Larghezza=Number((document.getElementById(MioNome).style.width).replace("px",""));
 var Altezza=Number((document.getElementById(MioNome).style.height).replace("px",""));
 var Intervallo;
 var dirX="destra", dirY="alto"
  this.step=function(intX,intY,limX,limY){
  
  if(Sinistra>limX)
   dirX="sinistra";
  if(Sinistra<0)
   dirX="destra" 
  if(dirX=="sinistra")
   intX=-intX;
  if(dirX=="destra")
   intX=intX;

  if(Alto>limY)
   dirY="alto";
  if(Alto<0)
   dirY="basso" 
  if(dirY=="alto")
   intY=-intY;
  if(dirX=="basso")
   intY=intY;

    Sinistra+=intX
  Alto+=intY
    document.getElementById(MioNome).style.left=Sinistra;
  document.getElementById(MioNome).style.top=Alto;
  }
 
 this.muovi=function(tempo, intX, intY, limX, limY){
  clearInterval(Intervallo);
  Intervallo=window.setInterval(function(oggetto){oggetto.step(intX, intY, limX, limY)},tempo,this);
 }
 this.inter=function(){
  clearInterval(Intervallo);
 }
  
}
function crea(){
  for(var n=0;n<document.getElementsByTagName("img").length;n++)
   {
    var DivId=document.getElementsByTagName("img")[n].id;
    window[DivId] = new oggetto(DivId);
   }
 
}


function clic(e){
 
  window[e.currentTarget.id].muovi(1,1,1,1200,100);
}

function over(e){
 window[e.currentTarget.id].inter();
}


</script>
<body onLoad="crea();">
<img id="ciccio" style="width:50px;height:50px;position:absolute;top:0px" src="pallone.gif" onClick="clic(event)" onMouseOver="over(event)">
<img id="pippo" style="width:50px;height:50px;position:absolute;top:100px" src="pallone.gif" onClick="clic(event)" onMouseOver="over(event)">
<img id="mimmo" style="width:50px;height:50px;position:absolute;top:200px" src="pallone.gif" onClick="clic(event)" onMouseOver="over(event)">
</body>
Il codice nuovo è marcato in verde.
In questo caso, costringo le palle a muoversi entro uno spazio ristretto, quasi un "tubo"!

Aggiunta di argomenti ai metodi: l'entità del singolo spostamento come parametri esterni all'oggetto.

Aggiungo come parametri esterni anche l'entità dello spostamento dell'oggetto in orizzontale e in verticale.
<script>
function oggetto(nome){
  var MioNome=nome;
 
 var Sinistra=Number((document.getElementById(MioNome).style.left).replace("px",""));
 var Alto=Number((document.getElementById(MioNome).style.top).replace("px",""));
 var Larghezza=Number((document.getElementById(MioNome).style.width).replace("px",""));
 var Altezza=Number((document.getElementById(MioNome).style.height).replace("px",""));
 var Intervallo;
 var dirX="destra", dirY="alto"
  this.step=function(intX,intY){
  
  if(Sinistra>300)
   dirX="sinistra";
  if(Sinistra<0)
   dirX="destra" 
  if(dirX=="sinistra")
   intX=-intX;
  if(dirX=="destra")
   intX=intX;

  if(Alto>300)
   dirY="alto";
  if(Alto<0)
   dirY="basso" 
  if(dirY=="alto")
   intY=-intY;
  if(dirX=="basso")
   intY=intY;

    Sinistra+=intX
  Alto+=intY
    document.getElementById(MioNome).style.left=Sinistra;
  document.getElementById(MioNome).style.top=Alto;
  }
 
 this.muovi=function(tempo, intX, intY){
  clearInterval(Intervallo);
  Intervallo=window.setInterval(function(oggetto){oggetto.step(intX, intY)},tempo,this);
 }
 this.inter=function(){
  clearInterval(Intervallo);
 }
  
}
function crea(){
  for(var n=0;n<document.getElementsByTagName("img").length;n++)
   {
    var DivId=document.getElementsByTagName("img")[n].id;
    window[DivId] = new oggetto(DivId);
   }
 
}


function clic(e){
 
  window[e.currentTarget.id].muovi(1,1,1);
}

function over(e){
 window[e.currentTarget.id].inter();
}


</script>
<body onLoad="crea();">
<img id="ciccio" style="width:50px;height:50px;position:absolute;top:0px" src="pallone.gif" onClick="clic(event)" onMouseOver="over(event)">
<img id="pippo" style="width:50px;height:50px;position:absolute;top:100px" src="pallone.gif" onClick="clic(event)" onMouseOver="over(event)">
<img id="mimmo" style="width:50px;height:50px;position:absolute;top:200px" src="pallone.gif" onClick="clic(event)" onMouseOver="over(event)">
</body>
In blu tutto il codice che ho dovuto aggiungere. Ho dovuto creare due variabili dirX e dirY esterne al metodo step() altrimenti a ogni ripetizione del metodo dietro la direzione del setInterval il valore delle variabili sarebbe stato resettato.

Aggiunta di argomenti ai metodi: il tempo come parametro esterno all'oggetto.

Per prima cosa, il metodo muovi() dell'oggetto DIV viene modificato accettando come argomento il tempo fra uno spostamento e l'altro dell'oggetto.
<script>
function oggetto(nome){
  var MioNome=nome;
 
 var Sinistra=Number((document.getElementById(MioNome).style.left).replace("px",""));
 var Alto=Number((document.getElementById(MioNome).style.top).replace("px",""));
 var Larghezza=Number((document.getElementById(MioNome).style.width).replace("px",""));
 var Altezza=Number((document.getElementById(MioNome).style.height).replace("px",""));
 var intX=1;
 var intY=1;
 var Intervallo;
  this.step=function(){
  
  if((Sinistra>900)||(Sinistra<0))
   intX=-intX
  if((Alto>600)||(Alto<0))
   intY=-intY
    Sinistra+=intX
  Alto+=intY
    document.getElementById(MioNome).style.left=Sinistra;
  document.getElementById(MioNome).style.top=Alto;
  }
 
 this.muovi=function(tempo){
  clearInterval(Intervallo);
  Intervallo=window.setInterval(function(oggetto){oggetto.step()},tempo,this);
 }
 this.inter=function(){
  clearInterval(Intervallo);
 }
  
}
function crea(){
  for(var n=0;n<document.getElementsByTagName("img").length;n++)
   {
    var DivId=document.getElementsByTagName("img")[n].id;
    window[DivId] = new oggetto(DivId);
   }
 
}


function clic(e){
 
  window[e.currentTarget.id].muovi(1);
}

function over(e){
 window[e.currentTarget.id].inter();
}


</script>
<body onLoad="crea();">
<img id="ciccio" style="width:50px;height:50px;position:absolute;top:0px" src="pallone.gif" onClick="clic(event)" onMouseOver="over(event)">
<img id="pippo" style="width:50px;height:50px;position:absolute;top:100px" src="pallone.gif" onClick="clic(event)" onMouseOver="over(event)">
<img id="mimmo" style="width:50px;height:50px;position:absolute;top:200px" src="pallone.gif" onClick="clic(event)" onMouseOver="over(event)">
</body>
...così da poter regolare "dall'esterno dell'oggetto" il tempo fra i singoli spostamenti dell'oggetto stesso.

Le palle si fermano una per una.

HAH!!!! Sono riuscito a realizzare il fatto che passandoci sopra con il mouse si fermano!

GRANDIOSO!!!
<script>
function oggetto(nome){
  var MioNome=nome;
 
 var Sinistra=Number((document.getElementById(MioNome).style.left).replace("px",""));
 var Alto=Number((document.getElementById(MioNome).style.top).replace("px",""));
 var Larghezza=Number((document.getElementById(MioNome).style.width).replace("px",""));
 var Altezza=Number((document.getElementById(MioNome).style.height).replace("px",""));
 var intX=1;
 var intY=1;
 var Intervallo;
  this.step=function(){
  
  if((Sinistra>900)||(Sinistra<0))
   intX=-intX
  if((Alto>600)||(Alto<0))
   intY=-intY
    Sinistra+=intX
  Alto+=intY
    document.getElementById(MioNome).style.left=Sinistra;
  document.getElementById(MioNome).style.top=Alto;
  }
 
 this.muovi=function(){
  clearInterval(Intervallo);
  Intervallo=window.setInterval(function(oggetto){oggetto.step()},20,this);
 }
 this.inter=function(){
  clearInterval(Intervallo);
 }
  
}
function crea(){
  for(var n=0;n<document.getElementsByTagName("img").length;n++)
   {
    var DivId=document.getElementsByTagName("img")[n].id;
    window[DivId] = new oggetto(DivId);
   }
 
}


function clic(e){
 
  window[e.currentTarget.id].muovi();
}

function over(e){
 window[e.currentTarget.id].inter();
}


</script>
<body onLoad="crea();">
<img id="ciccio" style="width:50px;height:50px;position:absolute;top:0px" src="pallone.gif" onClick="clic(event)" onMouseOver="over(event)">
<img id="pippo" style="width:50px;height:50px;position:absolute;top:100px" src="pallone.gif" onClick="clic(event)" onMouseOver="over(event)">
<img id="mimmo" style="width:50px;height:50px;position:absolute;top:200px" src="pallone.gif" onClick="clic(event)" onMouseOver="over(event)">
</body>
...con l'aggiunta del codice scritto in rosso.

Palle che rimbalzano in Firefox

Ecco tre palle che rimbalzano. Cliccando sopra ognuna delle tre palle, questa si libera e comincia a rimbalzare indipendentemente dalle altre.
Per il momento so farlo solo in Firefox.
<script>
function oggetto(nome){
  var MioNome=nome;
 
 var Sinistra=Number((document.getElementById(MioNome).style.left).replace("px",""));
 var Alto=Number((document.getElementById(MioNome).style.top).replace("px",""));
 var Larghezza=Number((document.getElementById(MioNome).style.width).replace("px",""));
 var Altezza=Number((document.getElementById(MioNome).style.height).replace("px",""));
 var intX=1;
 var intY=1;
 var Intervallo;
  this.step=function(){
  
  if((Sinistra>900)||(Sinistra<0))
   intX=-intX
  if((Alto>600)||(Alto<0))
   intY=-intY
    Sinistra+=intX
  Alto+=intY
    document.getElementById(MioNome).style.left=Sinistra;
  document.getElementById(MioNome).style.top=Alto;
  }
 
 this.muovi=function(){
  Intervallo=window.setInterval(function(oggetto){oggetto.step()},10,this);
 }
  
}
function crea(){
  for(var n=0;n<document.getElementsByTagName("img").length;n++)
   {
    var DivId=document.getElementsByTagName("img")[n].id;
    window[DivId] = new oggetto(DivId);
   }
 
}


function clic(e,){
 
  window[e.currentTarget.id].muovi();
}


</script>
<body onLoad="crea();">
<img id="ciccio" style="width:50px;height:50px;position:absolute;top:0px" src="pallone.gif" onClick="clic(event)">
<img id="pippo" style="width:50px;height:50px;position:absolute;top:100px" src="pallone.gif" onClick="clic(event)">
<img id="mimmo" style="width:50px;height:50px;position:absolute;top:200px" src="pallone.gif" onClick="clic(event)">
</body>

Creazione di oggetti DIV

Con Firefox funziona a meraviglia!
Basta cliccare su un oggetto DIV e questo fa un bel salto in avanti!

Devo provarlo con IE.

<script>
function oggetto(nome){
 var MioNome=nome;
 var str=document.getElementById(MioNome).style.left
 var Sinistra=Number(str.replace("px",""));
 this.step=function(){
  Sinistra+=100
  document.getElementById(MioNome).style.left=Sinistra;
 }
}  
 

function crea(){
 for(var n=0;n<document.getElementsByTagName("div").length;n++)
  {
  var DivId=document.getElementsByTagName("div")[n].id;
  window[DivId] = new oggetto(DivId);
  }
}


function azione(e){
 
 
 window[e.currentTarget.id].step();
 
}

</script>
<body onLoad="crea()">
<div id="ciccio" style="position:absolute;top:0px" onClick="azione(event)"> blablablablabla</div>
<div id="pippo" style="position:absolute;top:100px" onClick="azione(event)">ciao</div>
<div id="mimmo" style="position:absolute;top:200px" onClick="azione(event)">Buh</div>
</body>


Con Internet Explorer non funziona.
Continuo con Firefox e poi cercherò di imparare il dialetto Explorer...


Analisi:

1)function oggetto():
function oggetto(nome){
 var MioNome=nome;
 var str=document.getElementById(MioNome).style.left
 var Sinistra=Number(str.replace("px",""));
 this.step=function(){
  Sinistra+=100
  document.getElementById(MioNome).style.left=Sinistra;
 }
} 
Crea una variabile MioNome alla quale attribuire il parametro "nome";
Converti il valore dell'attributo "style.left" dell'elemento che si chiama con il nome in questione in un valore numerico e attribuiscilo alla variabile "Sinistra";
Crea una funzione locale "step()" che aumenta di 100 il valore sinistra e poi attribuisce questo valore all'attributo "style.left" dell'elemento che porta questo stesso nome.

2)function crea():
function crea(){
 for(var n=0;n<document.getElementsByTagName("div").length;n++)
  {
  var DivId=document.getElementsByTagName("div")[n].id;
  window[DivId] = new oggetto(DivId);
  }
}
Per ogni elemento del documento che ha per tag "div";
assegna alla variabile DivId il valore di id dell'elemento in questione;
Crea una variabile con il nome di quell'id e usala per creare un nuovo oggetto della classe "oggetto".

3)function azione()
function azione(e){
 
 
 window[e.currentTarget.id].step();
}
esegue il metodo step() dell'istanza della classe oggetto che porta il nome uguale a quello dell'id dell'oggetto da cui proviene l'evento.

domenica 15 gennaio 2012

Tentativi rudimentali di creare oggetti corrispondenti a elementi DIV...

Ecco, un rudimentale tentativo di creare un oggetto corrispondente a un elemento DIV
<script>

function oggetto(n){
 var str=document.getElementById(n).style.left;
 var sinistra=Number(str.replace("px",""));
 
 this.muovi=function(){
  document.getElementById(n).style.left=sinistra+100;
  
 }
}
function crea(e){
 var nome=e.currentTarget.id;
 window[nome];
 nome=new oggetto(e.currentTarget.id);
 nome.muovi();
}

</script>
<div id="ciccio" style="position:absolute;left:0px" onClicK="crea(event)"> blablablablabla</div>
Quando lo clicchi, si sposta in avanti.

Iniziamo a programmare a oggetti in JavaScript!

Ecco la creazione di un costruttore e di un oggetto:
<script>

function oggetto(){
 this.sinistra;
 this.alto;
 this.aumenta=function()
  {
   this.sinistra+=5;
  }
 
 
 
}
var questo = new oggetto();
questo.sinistra=12;
questo.aumenta();
alert(questo.sinistra);
</script>
Non è poi difficile...
Ora manipolo l'oggetto questo mediante un metodo modifica() creato nel contesto del costruttore:
<script>

function oggetto(){
 this.variabile=2;
 this.modifica = function(){
  this.variabile+=2;
 }
 
}
var questo = new oggetto();
questo.modifica();
alert(questo.variabile);
</script>
Bene. Il metodo modifica() ha aumentato di due il valore della proprietà variabile, e ottengo 4.

Ora però modifico la proprietà dall'esterno dopo averla modificata mediante il metodo interno modifica():
<script>

function oggetto(){
 this.variabile=2;
 this.modifica = function(){
  this.variabile+=2;
 }
 
}
var questo = new oggetto();
questo.modifica();
alert(questo.variabile);
questo.variabile=123;
alert(questo.variabile);
</script>
Ottengo 4 per effetto del metodo modifica() e poi 123 per effetto della modifica diretta dall'esterno della proprietà variabile.

Ora voglio che si crei una variabile privata in modo da non dare accesso dall'esterno alla modifica delle proprietà dell'oggetto.

<script>

function oggetto(){
 var variabile=2;
 this.modifica = function(){
  variabile+=2;
 }
 this.mostra=function(){
  alert(variabile);
 }
}
var questo = new oggetto();
questo.modifica();
questo.mostra();
questo.variabile=123;
questo.mostra();

</script>
Con il metodo modifica() ho sommato 2 alla variabile e ho ottenuto 4
Con il metodo mostra() ho mostrato il valore della variabile.
Ho messo in opera un tentativo di modificare dall'esterno il valore della variabile
La ripetizione del metodo mostra() mostra sempre un valore di 4, segno che dall'esterno non ho potuto modificare la variabile.

Ma la variabile viene "ripetuta" per ogni istanza dell'oggetto? Non sarà sempre quella?
Ora creo due oggetti...
<script>

function oggetto(){
 var variabile=2;
 this.modifica = function(){
  variabile+=2;
 }
 this.mostra=function(){
  alert(variabile);
 }
}
var questo = new oggetto();
var quello = new oggetto();

questo.modifica();
quello.modifica();
quello.modifica();
questo.mostra();
quello.mostra();
</script>
Ecco: ottengo 4 e 6. Questo significa che variabile è una variabile privata e diversa per ciascun oggetto!