domenica 2 gennaio 2011

Un orologio analogico (con le lancette) con javascript e jsDraw2D - Codice utile

Come promesso, dopo aver realizzato l'orologio digitale in javascript ( http://tinformatizzo.blogspot.com/2010/12/un-orologio-con-javascript-codice-utile.html ) e aver presentato in un altro post la libreria javascript jsDraw2Dhttp://tinformatizzo.blogspot.com/2011/01/disegno-2d-con-la-libreria-javascript.html ) per la grafica 2D nelle nostre pagine web.. ci accingiamo a costruire un OROLOGIO ANALOGICO !

Come al solito riporto di seguito il codice da me sviluppato per chi lo vuole usare (non in altri blog post o siti però..siete liberi di usarlo solo per i siti che costruite voi e non in altri per mostrare il codice!) e, come sempre, le relative spiegazioni per i più curiosi e vogliosi di imparare :)



<html>
<head>
<title>Orologio_analogico_javascript</title>

<script type="text/JavaScript" src="jsDraw2D.js"></script>

<script type="text/javascript">
var coseni = new Array();
coseni[0]=1;
coseni[1]=0.995;
coseni[2]=0.978;
coseni[3]=0.951;
coseni[4]=0.916;
coseni[5]=0.866;
coseni[6]=0.809;
coseni[7]=0.743;
coseni[8]=0.669;
coseni[9]=0.588;
coseni[10]=0.5;
coseni[11]=0.407;
coseni[12]=0.309;
coseni[13]=0.208;
coseni[14]=0.105;
coseni[15]=0;

var lan_sec_lung = 100;
var lan_min_lung = 90;
var lan_ora_lung = 60;

var x_centro = 200;
var y_centro = 200;

var centro = new jsPoint(x_centro,y_centro);

var col = new jsColor("blue");

var lan_sec = new jsPen(col,1);
var lan_min = new jsPen(col,3);
var lan_ora = new jsPen(col,8);
var bordo = new jsPen(col,4);

var punto_sec;
var punto_min;
var punto_ora;
var punto;

var ora;
var minuto;
var secondo;
var tempo;


function orologio()
{
tempo = new Date();

ora=tempo.getHours();
minuto=tempo.getMinutes();
secondo=tempo.getSeconds();

if (ora>12) {ora-=12;}

    var gr = new jsGraphics(document.getElementById("canvas"));

    gr.clear();


    if (secondo<=15)
    {punto_sec = new jsPoint(x_centro+Math.round(lan_sec_lung*coseni[15-secondo]),y_centro-Math.round(lan_sec_lung*coseni[secondo]));}
    else if (secondo>15 && secondo<=30)
    {punto_sec = new jsPoint(x_centro+Math.round(lan_sec_lung*coseni[secondo-15]),y_centro+Math.round(lan_sec_lung*coseni[30-secondo]));}
    else if (secondo>30 && secondo<=45)
    {punto_sec = new jsPoint(x_centro-Math.round(lan_sec_lung*coseni[45-secondo]),y_centro+Math.round(lan_sec_lung*coseni[secondo-30]));}
    else
    {punto_sec = new jsPoint(x_centro-Math.round(lan_sec_lung*coseni[secondo-45]),y_centro-Math.round(lan_sec_lung*coseni[60-secondo]));}


    if (minuto<=15)
    {punto_min = new jsPoint(x_centro+Math.round(lan_min_lung*coseni[15-minuto]),y_centro-Math.round(lan_min_lung*coseni[minuto]));}
    else if (minuto>15 && minuto<=30)
    {punto_min = new jsPoint(x_centro+Math.round(lan_min_lung*coseni[minuto-15]),y_centro+Math.round(lan_min_lung*coseni[30-minuto]));}
    else if (minuto>30 && minuto<=45)
    {punto_min = new jsPoint(x_centro-Math.round(lan_min_lung*coseni[45-minuto]),y_centro+Math.round(lan_min_lung*coseni[minuto-30]));}
    else
    {punto_min = new jsPoint(x_centro-Math.round(lan_min_lung*coseni[minuto-45]),y_centro-Math.round(lan_min_lung*coseni[60-minuto]));}

    if (ora<=3)
    {punto_ora = new jsPoint(x_centro+Math.round(lan_ora_lung*coseni[15-(ora*5)]),y_centro-Math.round(lan_ora_lung*coseni[(ora*5)]));}
    else if (ora>3 && ora<=6)
    {punto_ora = new jsPoint(x_centro+Math.round(lan_ora_lung*coseni[(ora*5)-15]),y_centro+Math.round(lan_ora_lung*coseni[30-(ora*5)]));}
    else if (ora>6 && ora<=9)
    {punto_ora = new jsPoint(x_centro-Math.round(lan_ora_lung*coseni[45-(ora*5)]),y_centro+Math.round(lan_ora_lung*coseni[(ora*5)-30]));}
    else
    {punto_ora = new jsPoint(x_centro-Math.round(lan_ora_lung*coseni[(ora*5)-45]),y_centro-Math.round(lan_ora_lung*coseni[60-(ora*5)]));}

gr.drawLine(lan_sec,centro,punto_sec);
gr.drawLine(lan_min,centro,punto_min);
gr.drawLine(lan_ora,centro,punto_ora);

punto = new jsPoint(x_centro-10,y_centro-lan_sec_lung-35);
gr.drawText("12", punto,null,col,null,"center");
punto = new jsPoint(x_centro+lan_sec_lung+20,y_centro-10);
gr.drawText("3", punto,null,col,null,"center");
punto = new jsPoint(x_centro-5,y_centro+lan_sec_lung+15);
gr.drawText("6", punto,null,col,null,"center");
punto = new jsPoint(x_centro-lan_sec_lung-30,y_centro-10);
gr.drawText("9", punto,null,col,null,"center");

gr.drawCircle(bordo, centro, lan_sec_lung+45);

 setTimeout("orologio()", 1000);
}

setTimeout("orologio()", 0);

</script>

</head>

<body>

<div id="canvas" style="position:relative;width:600px;height:300px;"></div>

</body>
</html>


Ed il risultato nel browser è il seguente:


Vi piace? spero di si.. ovviamente variando alcuni parametri potrete rimpicciolirlo o ingrandirlo come vi pare e piace.. o comunque modificarlo e farlo più attraente esteticamente :)


Ma ora vediamo il codice...


Innanzitutto ho importato la libreria jsDraw2D inserendo tra i tag <head></head> la riga:

<script type="text/JavaScript" src="jsDraw2D.js"></script>

Il file jsDraw2D.js in questo caso è stato messo nella stessa directory della pagina html creata.


Dopodichè iniziamo un po' ad analizzare lo script partendo dalle variabili che sono state definite:

var coseni = new Array();
coseni[0]=1;
coseni[1]=0.995;
coseni[2]=0.978;
coseni[3]=0.951;
coseni[4]=0.916;
coseni[5]=0.866;
coseni[6]=0.809;
coseni[7]=0.743;
coseni[8]=0.669;
coseni[9]=0.588;
coseni[10]=0.5;
coseni[11]=0.407;
coseni[12]=0.309;
coseni[13]=0.208;
coseni[14]=0.105;
coseni[15]=0;

In questo array ho salvato tutti i valori del coseno per angoli che vanno da 0 gradi a 90 gradi (con un salto di 6 gradi..cioè cos0° cos6° ... cos84° cos90°).
Questo per poter calcolare l'esatta direzione delle lancette nel primo quadrante che corrisponde alla porzione di orologio che va dalle ore 12 alle ore 3.
Forse vi starete chiedendo perchè non ho usato direttamente le funzioni Math.cos() (e Math.sin()).. la risposta che vi do è che, essendo funzioni che operano in virgola mobile, avevo seri problemi per via degli arrotondamenti (Fra l'altro cos0° cos90° non danno esattamente 1 e 0 ma dei numeri infinitesimali prossimi al valore intero.. per cui diventava lungo e noioso gestire questa situazione).


var lan_sec_lung = 100;
var lan_min_lung = 90;
var lan_ora_lung = 60;

var x_centro = 200;
var y_centro = 200;

Le righe sopra riguardano le variabili indicanti la lunghezza in pixel delle lancette dei secondi, minuti e ore.. mentre le ultime due riguardano la posizione in pixel del centro del nostro orologio (da cui partono le lancette).


var centro = new jsPoint(x_centro,y_centro);
Il centro dell'orologio. Si può notare l'utilizzo del costruttore jsPoint(..,..) della classe jsPoint definita nella libreria. In questo caso stiamo creando un'istanza di jsPoint per il punto centrale dell'orologio usando le variabili relative precedentemente definite e inizializzate.


var col = new jsColor("blue");
Il colore che ho utilizzato, ho usato solo il blu..

var lan_sec = new jsPen(col,1);
var lan_min = new jsPen(col,3);
var lan_ora = new jsPen(col,8);
var bordo = new jsPen(col,4);

Le righe sopra mostrano le variabili definite e inizializzate per la creazione delle penne con le quali verrà tracciato il disegno. Ho utilizzato dunque la classe jsPen allo scopo, il numero che vedete è la grandezza in pixel del segno lasciato dalla penna.


var punto_sec;
var punto_min;
var punto_ora;
var punto;

Queste variabili servono per tenere traccia del pixel finale per il tracciamento delle linee relative alle lancette dei secondi, minuti e ore. Infatti per tracciare la linea di una lancetta, si considera come pixel iniziale il centro dell'orologio mentre quello finale deve essere calcolato. La variabile punto servirà per inserire le scritte delle ore nell'orologio (12 3 6 9).

var ora;
var minuto;
var secondo;
var tempo;

Queste variabili terranno traccia dell'orario e quindi dell'ora, del minuto, del secondo che deve mostrare l'orologio.


Ora vi illustro il contenuto della funzione orologio() che si ricarica automaticamente dopo un secondo grazie alla linea in esso contenuta: setTimeout("orologio()", 1000);

Troviamo subito alcune linee, che per chi ha letto il post sull'orologio digitale, non dicono nulla di nuovo:

tempo = new Date();

ora=tempo.getHours();
minuto=tempo.getMinutes();
secondo=tempo.getSeconds();

if (ora>12) {ora-=12;}
 
Si ottiene l'informazione sulla data e l'orario attuale e poi si estraggono l'ora, il minuto ed il secondo. L'unica differenza è l'ultima riga che serve per trasformare l'ora dal formato 24H in formato 12H.
  
var gr = new jsGraphics(document.getElementById("canvas"));
gr.clear();

Con queste righe creo il "foglio" ogni volta e lo resetto.

    if (secondo<=15)
    {punto_sec = new jsPoint(x_centro+Math.round(lan_sec_lung*coseni[15-secondo]),y_centro-Math.round(lan_sec_lung*coseni[secondo]));}
    else if (secondo>15 && secondo<=30)
    {punto_sec = new jsPoint(x_centro+Math.round(lan_sec_lung*coseni[secondo-15]),y_centro+Math.round(lan_sec_lung*coseni[30-secondo]));}
    else if (secondo>30 && secondo<=45)
    {punto_sec = new jsPoint(x_centro-Math.round(lan_sec_lung*coseni[45-secondo]),y_centro+Math.round(lan_sec_lung*coseni[secondo-30]));}
    else
    {punto_sec = new jsPoint(x_centro-Math.round(lan_sec_lung*coseni[secondo-45]),y_centro-Math.round(lan_sec_lung*coseni[60-secondo]));}


if (minuto<=15)
{punto_min = new jsPoint(x_centro+Math.round(lan_min_lung*coseni[15-minuto]),y_centro-  Math.round(lan_min_lung*coseni[minuto]));}
else if (minuto>15 && minuto<=30)
{punto_min = new jsPoint(x_centro+Math.round(lan_min_lung*coseni[minuto-15]),y_centro+Math.round(lan_min_lung*coseni[30-minuto]));}
else if (minuto>30 && minuto<=45)
{punto_min = new jsPoint(x_centro-Math.round(lan_min_lung*coseni[45-minuto]),y_centro+Math.round(lan_min_lung*coseni[minuto-30]));}
else
{punto_min = new jsPoint(x_centro-Math.round(lan_min_lung*coseni[minuto-45]),y_centro-Math.round(lan_min_lung*coseni[60-minuto]));}

if (ora<=3)
{punto_ora = new jsPoint(x_centro+Math.round(lan_ora_lung*coseni[15-(ora*5)]),y_centro-Math.round(lan_ora_lung*coseni[(ora*5)]));}
else if (ora>3 && ora<=6)
{punto_ora = new jsPoint(x_centro+Math.round(lan_ora_lung*coseni[(ora*5)-15]),y_centro+Math.round(lan_ora_lung*coseni[30-(ora*5)]));}
else if (ora>6 && ora<=9)
{punto_ora = new jsPoint(x_centro-Math.round(lan_ora_lung*coseni[45-(ora*5)]),y_centro+Math.round(lan_ora_lung*coseni[(ora*5)-30]));}
else
{punto_ora = new jsPoint(x_centro-Math.round(lan_ora_lung*coseni[(ora*5)-45]),y_centro-Math.round(lan_ora_lung*coseni[60-(ora*5)]));}
 
Questa "marea" di righe fanno operazioni molto semplici per calcolare il punto finale delle linee relative alle lancette. In base al valore del secondo, del minuto e dell'ora, e grazie ai valori dei coseni (da 0° a 90°) definiti in precedenza, è possibile calcolare la posizione delle lancette sfruttando un po' le nozioni di trigonometria..


gr.drawLine(lan_sec,centro,punto_sec);
gr.drawLine(lan_min,centro,punto_min);
gr.drawLine(lan_ora,centro,punto_ora);

Con queste righe, utilizzando il metodo drawLine(penna,punto_iniziale,punto_finale) della classe jsGraphics, vengono disegnate le lancette.



punto = new jsPoint(x_centro-10,y_centro-lan_sec_lung-35);
gr.drawText("12", punto,null,col,null,"center");
punto = new jsPoint(x_centro+lan_sec_lung+20,y_centro-10);
gr.drawText("3", punto,null,col,null,"center");
punto = new jsPoint(x_centro-5,y_centro+lan_sec_lung+15);
gr.drawText("6", punto,null,col,null,"center");
punto = new jsPoint(x_centro-lan_sec_lung-30,y_centro-10);
gr.drawText("9", punto,null,col,null,"center");
gr.drawCircle(bordo, centro, lan_sec_lung+45);

Con queste righe invece si imposta ogni volta un punto in posizione diversa per posizionare le scritte (metodo drawText(..,..,..,..,..,..) della classe jsGraphics) delle ore (12 3 6 9) correttamente. L'ultima riga serve invece per tracciare la circonferenza  che contiene l'intero orologio. Questo è possibile grazie al metodo drawCircle(penna,centro,raggio) della classe jsGraphics.

Al di fuori della funzione troviamo la riga setTimeout("orologio()", 0); che io ho utilizzato strategicamente, preferendola ad altre soluzioni, per richiamare la prima volta la funzione orologio() al caricamento della pagina.

Per concludere bisogna inserire il div (il nostro foglio da disegno) tra i tag <body> e </body>:
<div id="canvas" style="position:relative;width:600px;height:300px;"></div>


Il gioco è dunque fatto! Alla prossima..  ciao!

Nessun commento:

Posta un commento