En aquesta pràctica es veurà com podem mesurar i mostrar el temps en les nostres aplicacions web. Introduirem inicialment els
conceptes bàsics que ens han de permetre utilitzar el rellotge del sistema i les formes més habituals de mostrar-lo en la pàgina web.

També veurem com podem implementar un cronòmetre que ens permeti mesurar intervals de temps acotats entre dos events, que poden ser originats per l'usuari o per altres events de la web.

Finalment es mostrarà un sistema de presentació més elaborat: un rellotge digital amb presentació mitjançant una matriu de punts.

Doncs bé, comencem?

  Elements del llenguatge en aquest capítol.
Mètode setTimeout() : Inicia un temporitzador.
Mètode clearTimeout() : Atura un temporitzador que estigui actiu.
Propietat status : Propietat de l'objecte window que conté el contingut que es veu a la barra d'estat.
Mètode split() : Descompon una cadena de text, segons l'element separador, creant un array dels elements separats.
Objecte Date : Ens permet treballar amb dates i hores.
Mètodes diversos de l'objecte Date.
 
1.-
L'hora actual.
La mesura del temps és una utilitat molt habitual en els llenguatges de programació i JavaScript no podia ser menys. El llenguatge ens proporciona un objecte d'aplicació específica per aquest concepte. És l'objecte Date.

L'objecte Date ens proporciona un conjunt de mètodes i propietats per treballar amb dates i hores. Qualsevol variable instanciada de l'objecte Date contindrà internament el nombre de mil·lisegons (positius o negatius) que han passat des del dia 1 de Gener de 1970.
per crear una instància de l'objecte Date, s'utilitza el constructor new de la forma següent:

    var data = new Date(paràmetres);

Els paràmetres poden ser:
    - El nombre de mil·lisegons transcorreguts des de l' 1 de Gener de 1.970.
    - Una cadena de text, en el format data i/o hora reconegut per l'objecte Date.
    - Un conjunt de valors numèrics, separats amb coma que representen a: any, mes, dia,
        hora, minut i segon. Els tres últims són opcionals.
    - Cap paràmetre.

Si no s'indica cap paràmetre, l'objecte Date agafarà la data i hora de l'ordinador que s'estigui utilitzant.

Un cop s'hagi creat una instància de l'objecte Date (en l'exemple anterior, la variable data) podrem aplicar sobre aquesta variable un conjunt de mètodes que ens permeten obtenir (get...) i assignar (set...) diferents valors que composen aquesta data.

Entre els més importants tenim:
        getHours().-Retorna l'hora.
        setHours().- Assigna l'hora.
        getMinutes().- Retorna el nombre de minuts.
        setMinutes().- Assigna el nombre de minuts.
        getSeconds().- Retorna el nombre de segons.
        setSeconds().- Assigna el nombre de segons.
        getFullYear().- Retorna l'any indicat amb quatre xifres.
        setFullYear().- Assigna l'any indicat amb quatre xifres.
        getMonth().- Retorna el número del mes. 0- Gener ... 11- Desembre
        setMonth().- Assigna el número del mes. 0- Gener ... 11- Desembre.
        getDate().- Retorna el número del dia.
        setDate().- Assigna el número del dia.
        getDay().- Retorna el número del dia de la setmana. 0- Diumenge ... 6- Dissabte.

El següent codi ens mostra uns exemples d'ús d'alguns d'aquests mètodes.

La funció horaAra() és la responsable de detectar la data i hora actual del rellotge del sistema, amb la línia var ara = new Date(), es declara una variable instanciada de l'objecte Date que conté la data i hora actual, ja que no s'ha passat cap paràmetre al constructor Date().

Un cop es té aquest valor, declarem i assignem la variable hora. El valor assignat és el que obtenim del mètode getHours() aplicat a la variable ara. Però abans fem una comprovació per si de cas el seu valor fos inferior a 10. Per fer-ho utilitzem l'operador condicional ternari ?:, tal com s'indica a la següent línia:

      (ara.getHours()<10) ? "0"+ara.getHours() : ara.getHours();

La condició és: (ara.getHours()<10). Si aquesta és certa, és a dir el valor de l'hora solament té un dígit, retornem un "0" afegit al valor retornat per ara.getHours(). De cas contrari, retornem el valor subministrat per ara.getHours() tal qual. Per tant, el contingut de la variable hora sempre contindrà dos dígits, un d'ells serà un zero a l'esquerra si és necessari.

Per a les variables minuts i segons es fa un procés similar a l'anterior.

Un cop es tenen els tres valors de les variables corresponents és necessari mostrar-los dins la pàgina web. La forma d'implementar aquesta operació pot ser molt diversa, i de fet, per les pàgines d'Internet es poden trobar moltes formes de mostrar la data i hora, algunes d'elles amb efectes vistosos i espectaculars.

En aquest primer exemple serem una mica més modestos i ens limitarem a mostrar-ho sobre dos elements molt simples d'implementar: un camp de formulari i la barra d'estat del navegador.

La línia document.forms.form1.contenidor.value = hora + ":" + minuts + ":" + segons; s'encarrega de mostrar el valor de hora, minuts i segons amb els : enmig dins un camp de text de nom contenidor situat dins un formulari de nom form1 situat en el bloc <body> de la pàgina.

La línia window.status = hora + ":" + minuts + ":" + segons; també representa el valor de hora, minuts i segons amb uns : entre mig, a la barra d'estat del navegador.

status és una propietat de l'objecte window que conté el valor que es mostra a la barra d'estat del navegador. Observeu que és molt senzill utilitzar aquesta sortida d'informació. De fet, aquesta propietat és molt utilitzada per fer-hi efectes de text. Ha Internet es pot veure moltes aplicacions que utilitzen aquesta propietat "status" per fer efectes més o menys elaborats amb cadenes de text. A més, és totalment compatible amb qualsevol tipus de navegador.

Per acabar la descripció de la funció ens queda la línia setTimeout("horaAra()",1000); Aquesta s'encarrega d'engegar un temporitzador que al cap de 1000 mil·lisegons torni a executar de nou la funció horaAra(). D'aquesta forma s'aconsegueix que els rellotges s'actualitzin cada segon. Proveu d'eliminar aquesta línia i observareu com el valor del rellotge no s'actualitza a no ser que es recarregui la pàgina.

La funció horaAra() s'invoca per primer cop mitjançant l'event onLoad situat a la directiva <body>.



<html>
<head>
<title>Rellotges</title>
<script language="JavaScript">

function horaAra()
{
  var ara = new Date();
  var hora = (ara.getHours()<10) ? "0"+ara.getHours() : ara.getHours();
  var minuts = (ara.getMinutes()<10)?"0"+ara.getMinutes():ara.getMinutes();
  var segons = (ara.getSeconds()<10)?"0"+ara.getSeconds():ara.getSeconds();
  document.forms.form1.contenidor.value = hora + ":" + minuts + ":" + segons;
  window.status = hora + ":" + minuts + ":" + segons;
  setTimeout("horaAra()",1000);
}
</script>
</head>

<body bgcolor="#FFFFE7"
onLoad="horaAra();">
<p><p><p>
<form name="form1">
<center>
  Hora actual:&nbsp; &nbsp;
<input type="text" name="contenidor" value="">
</center>
</form>
<p><p>
També ho pots veure a la barra d'estat:
</body>
</html>


 
2.- La data actual
Per obtenir la data actual indicada pel sistema es pot fer utilitzant un codi estructurat de forma similar a l'exemple anterior. Però, en aquest cas, s'ha de tenir en compte que getMonth() retorna el número de mes entre 0 i 11, i getDay() retorna el número de la setmana entre 0 i 6 (diumenge - dissabte). Per tant s'ha de fer la conversió.

És pot observar com s'assigna a una cadena la llista de noms de mesos i la llista de noms de dies de la setmana. Posteriorment amb el mètode split() es crea un array a nomMes i a nomDia, utilitzant com a separador l'espai (" "). Ara nomMes i nomDia són dos arrays, on el primer element serà el primer de la llista i l'últim element serà l'últim de la llista.
per referenciar cada element de l'array es podrà fer amb nomMes[index] i nomDia[índex], on índex és el valor que ens retorna getMonth() i getDay() respectivament.

Finalment, mitjançant document.write, s'escriu la cadena de text sobre el document per formar la data actual.

  ......      Codi dins el bloc <body>

<script language = "JavaScript">
  var ara=new Date();
  var nomMes="Gener Febrer Març Abril Maig Juny Juliol Agost Setembre Octubre
                                                                      Novembre Desembre";
  var nomDia="Diumenge Dilluns Dimarts Dimecres Dijous Divendres Dissabte";
  nomMes= nomMes.split(" ");
  nomDia= nomDia.split(" ");
  document.write(nomDia[ara.getDay()] + ", a " + ara.getDate() + " de " +
                                            nomMes[ara.getMonth()] + " de " + ara.getFullYear() );
</script>

  ......
 
3.- Cronòmetre
La implementació de cronòmetres consisteix en determinar un valor de Date inicial i un valor de Date al final de l'interval. La diferència serà el temps transcorregut.

Recordem que una variable instanciada de l'objecte Date conté el nombre de mil·lisegons des de l'1 de Gener de 1.970, per tant, la diferència entre dues variables tipus Date donarà com a resultat els mil·lisegons transcorreguts.

El següent exemple es basa en aquest concepte. Quan fem un clic a sobre el botó "Inicia", es crea una instància de Date en la variable abans. Aquesta variable conté el temps inicial. Posteriorment, dins el mateix controlador d'event onClick, s'invoca a la funció cron().

La funció cron() torna a instanciar una nova variable tipus Date de nom ara, i assigna a la propietat value del camp de text crono del formulari form1, la diferència respecte abans dividit per 1.000 per obtenir el resultat en segons.

També s'efectua la mateixa operació per assignar-ho a la propietat status de l'objecte window. És a dir, també es veurà el comptador a la barra d'estat de la finestra.

En acabar de fer les dues assignacions per mostrar el resultat de la diferència, s'engega un temporitzador mitjançant setTimeout(). La funció d'aquest temporitzador és tornar a invocar la funció cron() al cap de 10 mil·lisegons. A la vegada, setTimeout() retorna un valor a tID, el valor retornat és l'identificador numèric del temporitzador que està en execució.

Quan desitgem aturar el cronòmetre, farem clic a sobre del botó "Atura", el seu event onClick invocarà a la funció clearTimeout() passant-li el paràmetre corresponent a l'identificador del temporitzador que estigui actiu en aquest moment. La funció clearTimeout() atura el temporitzador indicat en el seu paràmetre tID. Amb això aconseguim aturar el cronòmetre.

Observeu com a la variable abans solament se li assigna un valor al principi del procés, quan es fa clic a sobre de "Inicia". En canvi, a la variable ara se li assigna un valor cada cop que s'invoca a la funció cron() (cada 10 ms.). Lògicament, el temps transcorregut (ara - abans) cada cop serà més gran.

Una aplicació similar a la que s'ha descrit en aquest apartat consisteix a mesurar el temps que un visitant ha estat visualitzant una pàgina web. Quan tanqueu aquesta pàgina web, us apareixerà un missatge alert() que us mostrarà el temps que heu estat visualitzant la pàgina.

L'efecte s'ha aconseguit de forma similar a la descrita pel cronòmetre, desant en una variable el temps actual mitjançant l'event onLoad situat en la directiva <body>. En tancar la pàgina, mitjançant un altre event onUnload() situat a la directiva <body> es torna a determinar el temps actual i es mostra mitjançant l' alert() la diferència de temps entre les dues variables.

<html>
<head>
<title>Cronòmetre</title>
<script language="JavaScript">
  var abans;
  var tID;
  function cron()
  {
    var ara=new Date();
    document.forms.form1.crono.value=(ara-abans)/1000 + " s.";
    window.status=(ara-abans)/1000 + " s.";
    tID=setTimeout("cron()",10);
  }
</script>
</head>

<body bgcolor="#FFFFE7">
  <form name="form1">
  <input type="text" name="crono" value="">&nbsp;
  <input type="button" value="Inicia"
onClick="abans=new Date(); cron();">&nbsp;
  <input type="button" value="Atura"
onClick="clearTimeout(tID);">
  </form>
</body>
</html>

 
4.-
Millorem la presentació de sortida.
Fins ara ens hem limitat a mostrar la sortida del rellotge, data i cronòmetre en tres elements relativament fàcils d'implementar com són un camp de text de formulari, la barra d'estat del navegador i directament sobre el bloc 'body' del document amb document.write().

Si volem millorar l'aspecte gràfic de sortida de les dades es pot fer mitjançant la utilització d'estils, però, en aquest apartat es proposa la creació de dígits numèrics mitjançant una matriu de punts.

La matriu de punts de cada dígit és de 3 columnes per 5 files. En cada matriu assenyalem amb un " * " el punt que ha de quedar activat a ON i amb un " · " el punt que ha de quedar a OFF. Tot el conjunt de dígits numèrics i símbol " : " format amb matrius de punts s'introdueix en una variable de cadena de nom caràcters .

En la secció de codi es pot veure la variable "caràcters". S'ha indicat mitjançant línies numerades per veure millor com estan formats els caràcters, però, en la implementació dins el codi, la variable ha de tenir tots els punts i asteriscs indicats en una sola línia, sense cap espai, de la forma següent:

                    var caracters = "·*·*·**·**·*·*··*·**··*· .................................. ";

Les variables col i fil han de contenir el nombre de columnes i files de la matriu, respectivament.

La funció digital() rep com a paràmetre una cadena de text, de longitud indeterminada, formada per caràcters dels que estan definits dins de la variable "caràcters". Seguidament, analitza cadascun dels caràcters de la cadena de text i extreu la seva representació segons la matriu de punts.

En funció de quina sigui la representació del caràcter, assignarà una imatge de nom "on.gif" si és un asterisc o bé una imatge de nom "off.gif" si és un punt. D'això se n'encarrega la funció auxiliar ferImg().

En aquest exemple s'ha utilitzat la imatge per a "on.gif" i la imatge per a "off.gif". Aquestes imatges es poden modificar pel que fa a la mida i colors per obtenir altres resultats gràfics.

La funció "ferImg()" rep com a paràmetres cad, f i ncar. cad és un array format per tots els caràcters de la cadena "caràcters". f és el número de fila que s'està formant en aquest moment i ncar és la posició del caràcter dins de l'array (el 0 ocupa la posició 0, el 1 la posició 1, el : la posició 10 .... , teniu en compte que una posició d'un caràcter dins de l'array ocupa (fil*col) elements de l'array.

Finalment, la funció digital() retorna una taula que conté les referències HTML per mostrar les imatges "on.gif" i "off.gif", ordenades adequadament per formar el text desitjat. Aquesta taula es pot situar on es desitgi dins la pàgina web.

Aquesta funció és molt versàtil i permet altres modificacions. Noteu que no estem pas restringits a utilitzar solament dígits numèrics. Podem crear tot l'alfabet amb majúscules, minúscules i caràcters especials i afegir-los a la variable "caràcters" i a la vegada, també s'hauran d'afegir els nous caràcters dins l'estructura "case", de forma similar a com s'ha fet entre les línies 10 i 20 de la funció digital().

Per millorar l'aspecte dels dígits i donar-los més "resolució" es pode crear matrius de punts amb més files i columnes (p.e. 7x5, 9x5, etc.) i incorporar-los a la variable "caràcters". En aquest cas s'hauran de modificar també les variables "fil" i "col".

Modificant les imatges "on.gif" i "off.gif", pel que fa a colors i mida, es poden aconseguir altres variacions d'efecte estètic.

1  var caracters="
2   ·  *  · 
3   *  ·  *
4   *  ·  *
5   *  ·  *
6   ·  *  · 
 
7    ·  *  ·
8    *  *  ·
9    ·  *  ·
10  ·  *  ·
11  ·  *  · 
12  ·  *  · 
13  *  ·  *
14  ·  *  · 
15  *  ·  · 
16  *  *  *
 
17  *  *  · 
18  ·  ·  * 
19  ·  *  · 
20  ·  ·  * 
21  *  *  ·  
22  *  ·  · 
23  *  ·  *
24  *  *  *
25  ·  ·  * 
26  ·  ·  *

27  *  *  * 
28  *  ·  · 
29  *  *  · 
30  ·  ·  * 
31  *  *  · 
32  ·  *  · 
33  *  ·  · 
34  *  *  · 
35  *  ·  * 
36  ·  *  · 

37  *  *  * 
38  ·  ·  * 
39  ·  *  · 
40  ·  *  · 
41  ·  *  · 
42  ·  *  · 
43  *  ·  * 
44  ·  *  · 
45  *  ·  * 
46  ·  *  · 

47  ·  *  · 
48  *  ·  * 
49  ·  *  * 
50  ·  ·  * 
51  ·  *  · 
52  ·  ·  · 
53  ·  *  · 
54  ·  ·  · 
55  ·  *  · 
56  ·  ·  · 
57  ";

var col = 3;
var fil = 5;

1  function digital(text)
2  {
3    var car;
4    var cad = caracters.split("");
5    var taula="<table border='0' cellspacing='0' cellpadding='0'>\n";
6    for (var f=0; f<fil; ++f) {
7      taula += "<tr><td>"
8      for (car=0; car<text.length; ++car) {
9        switch (text.substring(car,car+1)) {
10         case '0': taula += ferImg(cad,f,0);break;
11         case '1': taula += ferImg(cad,f,1);break;
12         case '2': taula += ferImg(cad,f,2);break;
13         case '3': taula += ferImg(cad,f,3);break;
14         case '4': taula += ferImg(cad,f,4);break;
15         case '5': taula += ferImg(cad,f,5);break;
16         case '6': taula += ferImg(cad,f,6);break;
17         case '7': taula += ferImg(cad,f,7);break;
18         case '8': taula += ferImg(cad,f,8);break;
19         case '9': taula += ferImg(cad,f,9);break;
20         case ':' : taula += ferImg(cad,f,10);break;
21       }
22       if (car != text.length-1) taula += "<img src='off.gif'>";
23     }
24     taula += "</td></tr>\n";
25   }
26   taula += "</table>";
27   return taula;
28 }


1  function ferImg(cad,f,ncar)
2  {
3    var img = "";
4    for (var i=0; i<col; ++i) {
5      img += "<img src='";
6      img += (cad[col*fil*ncar+col*f+i] == '*')?"on.gif":"off.gif";
7      img += "'>";
8    }
9    return img;
10 }


<html>
<head>
<title>Rellotge digital</title>
<script language="JavaScript">
  ...... introduïm la variable "caracters" .....
  ...... introduïm les variables "col" i "fil" .....
  ...... introduïm la funció digital() .....
  ...... introduïm la funció ferImg() .....
</script>
</head>
<body>
<script language="JavaScript">
  var ara = new Date();
  var hora = (ara.getHours()<10)?"0"+ara.getHours():ara.getHours();
  var minuts = (ara.getMinutes()<10)?"0"+ara.getMinutes():ara.getMinutes();
  var segons = (ara.getSeconds()<10)?"0"+ara.getSeconds():ara.getSeconds();

  document.write( digital(hora + ":" + minuts + ":" + segons) );
</script>
</body>
</html>