Sunday, February 22, 2009

Dal wallpaper al web

. Sunday, February 22, 2009

Qualche giorno fa curiosando su Smashing Magazine la mia attenzione è stata catturata da un wallpaper (disegnato da Liam J Moore) del seguente post: Desktop Wallpaper Calendar: February 2009. Mi è piaciuto così tanto che ho pensato di trasformare il tutto in un calendario per il web facendo uso dell’ormai insostituibile jQuery.
Ma partiamo con ordine indicando tutti gli strumenti da lavoro:
1)jQuery per la parte JavaScript;
2)CSS;
3)un controllo calendar: jQuery Datepicker;

Il primo passo consiste nel creare il markup della pagina:

   1: <table id="pagerYear">
   2:   <tr>
   3:     <td><span id="txtYear">2009</span></td>
   4:     <td align="right"><img src="img/meno.jpg" onclick="minYear()"/> 
<img src="img/piu.jpg" onclick="plusYear()"/></td>
   5:   </tr>
   6: </table>
   7: <div style="vertical-align:bottom; height:200px; position:absolute">
   8:   <div id="mese_gennaio"><p>Gen</p></div>
   9:   <div id="mese_febbraio"><p>Feb</p></div>
  10:   <div id="mese_marzo"><p>Mar</p></div>
  11:   <div id="mese_aprile"><p>Apr</p></div>
  12:   <div id="mese_maggio"><p>Mag</p></div>
  13:   <div id="mese_giugno"><p>Giu</p></div>
  14:   <div id="mese_luglio"><p>Lug</p></div>
  15:   <div id="mese_agosto"><p>Ago</p></div>
  16:   <div id="mese_settembre"><p>Set</p></div>
  17:   <div id="mese_ottobre"><p>Ott</p></div>
  18:   <div id="mese_novembre"><p>Nov</p></div>
  19:   <div id="mese_dicembre"><p>Dic</p></div>
  20:   <div id="divCal" style="display:none; position:absolute">
  21:     <span id="calendar"></span>  
  22:   </div>
  23: </div>


Risultato:
CalendarWallpaper4

Per quanto riguarda il CSS usato nella pagina potete scaricarlo da qui:
CSS Page

Fin qui tutto molto semplice, si è trattato di inserire un numero di tag div pari al numero di mesi. Ma come si può, notare dal wallpaper i singoli mesi dovrebbero alla selezione dell’utente abbassarsi/alzarsi.
Personalmente ho optato per l’effetto Size che consente di ridimensionare l’elemento specificando valori per le proprietà width e height.
In prima battuta la funzione può essere così impostata:

   1: $(function() {
   2:   $("div[id^='mese_']").toggle(function() {
   3:     $(this).effect("size", {
   4:       to: {
   5:         width: 60,
   6:         height: 100
   7:         }, origin: ['200', '0']
   8:       }, 1000);
   9:     }, 
  10:     function() {
  11:     $(this).effect("size", {
  12:       to: {
  13:         width: 60,
  14:         height: 200
  15:       }, origin: ['100', '0']
  16:     }, 1000);
  17:   });
  18: });

Per ogni div la cui proprietà id inizia per “mese_” tramite l’effetto Toggle altero la visualizzazione (riga 2). La prima volta per effetto del Size la dimensione del div selezionato passerà da un’altezza pari a 200px a una di 100px. La seconda volta la sua dimensione verrà riportata a quella originaria.
Così facendo però ogni mese può essere ridimensionato ad un’altezza pari a 100px.


CalendarWallpaper1

Quello che invece mi sono proposto di ottenere è di avere solo un mese alla volta ridimensionato, tutti gli altri devono riconquistare la loro dimensione originaria: 200px.

Questo risultato si può ottenere agendo sui Trigger. La funzione vista in precedenza si arricchisce nel seguente modo:

   1: var idOldDivSized = '';
   2: $(function() {
   3:   $("div[id^='mese_']").toggle(function() {
   4:     if (idOldDivSized != "") {
   5:       $("#" + idOldDivSized + "").trigger('click');
   6:     }
   7:     $(this).effect("size", {
   8:       to: {
   9:         width: 60,
  10:         height: 100
  11:       }
  12:       , origin: ['200', '0']
  13:     }, 1000);
  14:     idOldDivSized = this.id;
  15:     }, function() {
  16:     $(this).effect("size", {
  17:       to: {
  18:         width: 60,
  19:         height: 200
  20:       }, origin: ['100', '0']
  21:     }, 1000);
  22:     idOldDivSized = "";
  23:     $(this).parent().css("bottom", "0px");
  24:   });
25:});

Le nuove righe sono: 1, 3, 4, 5, 14, 22 e 23. Sostanzialmente tramite il trigger possiamo innescare l’evento sul div precedentemente selezionato (riga 4 e 5). Quest’ultima informazione viene salvata in una variabile globale: idOldDivSized (riga 14 e 22). La riga 23 è un fix per il browser IE.

In questo modo ottengo:CalendarWallpaper2
Non rimane che dare uno sguardo ai passi necessari a far comparire il controllo calendario al di sotto del mese. Per semplicità ho scelto un controllo già bello e pronto: Datepicker. Per chi fosse interessato ad una collezione di controlli
caldendar in JavaScript vi rimando al seguente post:
A collection of 14 Excellent JavaScript Date Pickers
Il controllo nella fattispecie è personalizzabile in mille aspetti. Per esempio si può decidere se visualizzare una dropdownlist contenente gli anni/mesi, modificare lo stile ecc.
Nel mio caso il calendario deve mostrare solo i giorni. I parametri da settare sono ben documentati:

   1: $("#calendar").datepick({ changeMonth: false,
   2:     changeYear: false
   3: });

Per eliminare la parte superiore del controllo in cui vengono mostrati gli elementi prev e next l’unica soluzione che ho trovato è stata quella di intervenire sul CSS, in particolar modo sulla classe: datepick-links, settando la proprietà display a none.
Ancora una volta modifichiamo la funzione vista fino a questo momento:

   1: var idOldDivSized = '';
   2: $(function() {
   3:   $("div[id^='mese_']").toggle(function() {
   4:   if (idOldDivSized != "") {
   5:     $("#" + idOldDivSized + "").trigger('click');
   6:   }
   7:   $(this).effect("size", {
   8:     to: {
   9:       width: 60,
  10:       height: 100
  11:     }
  12:     , origin: ['200', '0']
  13:   }, 1000);
  14:   idOldDivSized = this.id;
  15:   modifyCal($(this).parent().css("left"), idOldDivSized);
  16:   }, function() {
  17:     $('#divCal').css("display", "none");
  18:     $(this).effect("size", {
  19:       to: {
  20:         width: 60,
  21:         height: 200
  22:       }, origin: ['100', '0']
  23:     }, 1000);
  24:     idOldDivSized = "";
  25:     $(this).parent().css("bottom", "0px");
  26:   });
27:});

Le nuove righe sono: 15 e 17. La riga 17 non merita di essere commentata più di tanto, nel senso che non fa altro che rendere non visibile il div che contiene il controllo calendario.

Invece la riga 15 è estremamente interessante. In essa richiamo la funzione modifyCal (responsabile della visualizzazione del calendario), passando come parametri una posizione e l’id del div selezionato (es: “mese_marzo”).
Qualcuno forse avrà notato che la posizione che passo come parametro è quella dell’oggetto parent e non come ci si può immaginare quella dell’oggetto div/mese scelto:
$(this).css(“left”)
Il motivo è da ricercare nell’effetto Size. Non sono andato troppo in profondità con l’analisi ma osservando quello che accade tramite Firebug sembra che il div da ridimensionare viene incapsulato in un div contenitore il quale contiene le informazioni di posizione (per chi fosse interessato consiglio di iniziare col guardare lo script dell’effetto):
CalendarWallpaper3 
Ecco la funzione modifyCal:

   1: function convertMonths(month) {
   2:   switch (month){  
   3:     case "mese_gennaio":  
   4:       return 1;  
   5:     case "mese_febbraio":  
   6:       return 2;
   7:     case "mese_marzo":  
   8:       return 3;
   9:     case "mese_aprile":
  10:       return 4;
  11:     case "mese_maggio":
  12:       return 5;
  13:     case "mese_giugno":
  14:       return 6;
  15:     case "mese_luglio":
  16:       return 7;
  17:     case "mese_agosto":
  18:       return 8;
  19:     case "mese_settembre":
  20:       return 9;
  21:     case "mese_ottobre":
  22:       return 10;
  23:     case "mese_novembre":
  24:       return 11;
  25:     case "mese_dicembre":
  26:       return 12;
  27:   }
  28: }
  29:  
  30: function modifyCal(positionLeft, month) {
  31:   $('#divCal').css("top", "200px");
  32:   $('#divCal').css("display", "block");
  33:  
  34:   var da = new Date(parseInt($('#txtYear').html()), convertMonths(month) - 1, 1);
  35:   $("#calendar").datepick('destroy');
  36:   $("#calendar").datepick({ changeMonth: false,
  37:       changeYear: false,
  38:       defaultDate: da
  39:    });
  40:    $('#theme').attr('href', "jquery.datepick." + month + ".css");
  41:    $("#divCal").animate({
  42:        left: positionLeft
  43:    }, 1500);
  44: }

Viene generata una data di default da assegnare al calendario ( riga 34). Il div viene spostato tramite animazione nella posizione indicata attraverso il parametro positionLeft (riga 41 a 43). Infine viene caricato il CSS del calendario modificando l’attributo href del tag style (riga 40):


   1: <link href="jquery.datepick.css" rel="stylesheet" type="text/css" id="theme"/>

Significa che ogni mese è corredato di un file CSS (modificati opportunamente). Il nome di questo file è composto da “jquery.datepick.” più l’id del div/mese più l’estensione css.
Infine la pulsantiera in alto che permette di andare avanti ed indietro con gli anni si basa su due semplici funzioni: minYear e plusYear:


   1: function minYear() {
   2:   $('#txtYear').html(parseInt($('#txtYear').html()) - 1);
   3: }
   4:  
   5: function plusYear() {
   6:   $('#txtYear').html(parseInt($('#txtYear').html()) + 1); 
   7: }

Personalmente ho trovato l’esercizio notevolmente stimolante e l’uso di jQuery ha reso tutto molto più divertente:
CalendarWallpaper6
Come al solito buono studio!!!.
NB: test effettuati sui principali browser:
IE 7, Firefox 3, Chrome ed Opera 9.

4 commenti:

liam j said...

Hi there.

I'm Liam J Moore. What exactly have you done to my calendar design? I can't read Spanish, but I like what I think I see here!

Best,
Liam

Pierluca said...

Hi Liam
the wallpaper you made truly inspired me. It gave me the hint to work on a web calendar.
The post describes the step to realize it with JQuery Framework.

liam j said...

Hi Pierluca,

Have you got that web calendar finished? I would be interested to see how it turned out :)

Pierluca said...

Hi Liam,
the web calendar I developed was intended to be an exercize.. Here I hosted the prototype for you to see. Enjoy.
http://lab.in-folio.it/Prototype/PrototypeCalendar.html

Post a Comment