• Non ci sono risultati.

Sviluppo di nuove funzionalità con l’utilizzo di JavaScript

3. Sviluppo dell’applicazione mobile con Apache Cordova

3.4 Sviluppo di nuove funzionalità con l’utilizzo di JavaScript

Nel capitolo precedente è stato esplicato come la modal window è stata dichiarata in JavaScript e come le è stato assegnato un stile. Nel capitolo corrente verrà spiegato il comportamento tramite file JavaScript.

Nell’illustrazione 33 viene visualizzato il blocco di codice che seleziona tramite i metodi document.getElementById e document.getElementByTagName:

• la finestra (slide1) a tutto schermo (semitrasparente) che contiene la modal window con i suoi elementi;

• la modal window effettiva (info);

• il tag span contenente la croce di chiusura della finestra;

successivamente vengono visualizzati i metodi relativi alle azioni dell’utente (click). Tra questi si nota la visualizzazione del tag div come elemento di blocco, al click sul pulsante info (modal.style.display = "block"). Per la chiusura invece vengono utilizzati dei listener, uno

sulla parte semitrasparente della modal window (tratto caratteristico dei listener delle applicazioni mobili), ed un’altro sulla sempiterna croce di chiusura.

Proseguendo nello studio in alcune parti del codice si può trovare un nuovo comportamento per quanto concerne il movimento dei bottoni di riscaldamento e raffreddamento:

Una delle scelte implementative è consistita nel creare un effetto grafico capace di ruotare i bottoni in senso orario (riscaldamento) e in senso antiorario (raffreddamento). L’illustrazione 34 mostra la funzione che esegue questo comportamento; essa controlla quale elemento selezionato del CSS è stato passato come input del metodo. Se equivale al bottone avente come id warmer, l’angolo di rotazione viene incrementato di trenta gradi, altrimenti, viene decrementato dello stesso valore54.

I nuovi bottoni, che sono delle immagini caricate tramite CSS, come background del tag input55

hanno la seguente forma:

54 Specificare nel secondo ramo condizionale che il bottone debba avere come id colder è superfluo. Il metodo

buttonRotation viene chiamato solo ed esclusivamente nelle funzioni warm() e cold() quindi non è necessario

specificare che sia colder l’identificatore nel secondo ramo del istruzione condizionale.

55 Codice CSS per il caricamento in background delle immagini nel bottone e dimensioni e posizionamento all’interno della pagina: #warmer, #colder{ width: 126px; height: 121px; border: none; } #warmer{

background: url(../img/warm.png) no-repeat; position: fixed;

left: 0; bottom: 0; }

#colder{

background: url(../img/cold.png) no-repeat; position: fixed;

bottom: 0; right: 0; }

Nel capitolo 3.4 stato osservato come, tramite CSS, sono stati rimossi alcuni elementi superflui generati in fasi di building da Cordova. Similmente, facendo dei tentativi con diverse versioni di JQuery, si è notato che, con la versione scelta, veniva ripetuta una scritta, che inizialmente era sita all’interno dei bottoni, che adesso è apparsa esattamente fuori da essi. Non è stato possibile rimuovere tali scritte indesiderate con i selettori CSS poiché non rientravano in alcun tipo di elemento, tale che potesse essere stato intercettato dal CSS. Per questo motivo è stato usata la seguente funzione in JavaScript:

function rmValue(identifier){ $("#"+identifier+" div").contents().filter(function () { return this.nodeType === 3; }).remove(); } […] rmValue("bottone");

La funzione rmValue si occupa di eliminare le scritte che si ripetono all’infuori di un bottone, prendendo come riferimento l’identificatore di un elemento, e il figlio div, immediatamente precedente alle scritte superflue.

Nel momento in cui l’applicazione web originaria è stata inserita all’interno di un progetto Cordova al momento dell’esecuzione su device si è notato che i pulsanti di riscaldamento e raffreddamento non portavano a termine il loro funzionamento. Dopo innumerevoli tentativi è stato osservato che il problema risiedeva nei listener, i quali avevano due funzioni associate:

var nodeWarm = $_id("warmer"); nodeWarm.onmousedown = cl1_plus_t; nodeWarm.onmouseup = cl1_plus_f; […]

var nodeCold = $_id("colder"); nodeCold.onmousedown = cl2_minus_t; nodeCold.onmouseup = cl2_minus_f;

I metodi associati ai bottoni che non hanno avuto funzionamento all’interno dei device sono stati onmousedown e onmouseup. Il non-funzionamento è facilmente intuibile poiché sui dispositivi mobili non è presente il mouse, e quindi non viene riconosciuto il mouse premuto per un lasso di tempo (onmousedown) e il mouse non premuto (onmouseup). Per ovviare a questo problema occorre utilizzare JQuery-mobile, il quale fornisce due funzioni simili che intercettano sia la pressione delle dita dall’utente di una applicazione mobile, sia il click del mouse su browser web. Quindi, il nuovo blocco di codice risulta essere:

$(document).on("vmousedown", "#warmer", cl1_plus_t); $(document).on("vmouseup", cl_plusMinus_f);

$(document).on("touchend", cl_plusMinus_f); […]

$(document).on("vmousedown", "#colder", cl2_minus_t); document.getElementById("colder").disabled = true;

I metodi che rendono possibile l’utilizzo del funzionamento sia su browser che su desktop, sono vmousedown e vmouseup entrambi utilizzati esattamente come nel codice soprastante; in più, a gestire meglio la fine dell’utilizzo dei pulsanti, si trova la funzione touchend che indica che non esiste più alcuna pressione, sia del mouse che delle dita, sull’applicazione. L’aggiunta di questa parte di codice è stata necessaria, poiché, dopo diverse prove di funzionamento dell’applicazione, è stato osservato che se un puntatore, durante la pressione, veniva spostato da un’altra parte, che non sia stata il bottone, il funzionamento di quest’ultimo non smetteva. Così facendo si è limitato questo mal funzionamento limitando i bottoni entro la loro area di utilizzo.

Una delle scelte implementative più salienti, è stata il fissaggio dell’orientamento dell’applicazione sui dispositivi mobili in posizione orizzontale, utilizzando il seguente codice:

window.screen.orientation.lock('landscape-primary');

Questo ha permesso di poter modellare il layout in maniera più semplice, senza tenere conto di due tipi di situazioni (verticale e orizzontale) e, consequenzialmente, l’apparenza dell’applicazione risulta essere molto simile a quella di un joystick per i videogame. Questa scelta implementativa aiuta nello sviluppo di un listener che andrà a cambiare direzione delle particelle al momento dell’inclinazione del dispositivo, come se fossero attratte dalla gravità.

Per attuare questo comportamento è stata utilizzata una funzione di JavaScript (o meglio un listener sulla finestra o view) che legge alcuni valori dell’accelerometro del dispositivo:

window.addEventListener('deviceorientation', function(eventData) { var tilt = (eventData.beta*Math.PI)/180;

fx=Math.sin(tilt);

fy=Math.cos(tilt)*(eventData.gamma<0 ? -1:1); }, false);

Questa funzione esegue diverse espressioni che hanno come obiettivo quello di aggiornare due variabili globali dedite all’aggiornamento della forza della gravità sulle particelle, ovvero fx e fy; a favorire ciò agiscono altre variabili, facenti parte dell’oggetto eventData, che agiscono su diverse inclinazioni dei dispositivi. Esse sono alpha, beta, gamma (restituiti dall’oggetto eventData come eventData.beta, eventData.alpha, eventData.gamma), variabili dell’accelerometro che si occupano di gestire le seguenti inclinazioni in termini di gradi, illustrate nella seguente figura:

Le variabili utilizzate dall’oggetto eventData sono state beta e gamma, che, agendo aritmeticamente sulle variabili globali fx e fy, aggiornano tutti i gradi di inclinazione del dispositivo in termini di gradi, successivamente convertiti in radianti.

Per evitare che, durante la rotazione di centottanta gradi, venga letto dal sensore lo stesso valore dell’inclinazione iniziale dell’applicazione56 è stata inserito un controllo su gamma che esegue

un’espressione condizionale in base al suo valore (se gamma è minore di zero allora viene moltiplicato per -1, altrimenti viene moltiplicato per 1).

Nell’illustrazione soprastante si può osservare come, sottoposte all’effetto della gravità modellata sulla lettura dei sensori, le particelle seguano l’inclinazione del dispositivo, come se un liquido 56 Partendo dalla posizione orizzontale fissa iniziale, e ruotando il dispositivo di 180, le variabili dell’accelerometro

acquisiscono gli stessi valori della posizione iniziale; ciò implica che durante la rotazione di 180 gradi non sarà 37. Illustrazione: Particelle di alcol terziar-butilico sottoposte alla forza di gravità

(l’alcol terziar-butilico nell’esempio fornito) fosse contenuto in un bicchiere sottoposto appunto, ad un’inclinazione di più o meno 45 gradi.

Un’altra delle scelte progettuali è consistita nel colorare una sola particella di un colore completamente opposto rispetto alle restanti particelle; questa scelta è nata dal fatto di poter vedere più nitidamente il comportamento di una singola particella favorendo l’apprendimento degli alunni che andranno ad interagire con l’applicazione mobile.

La funzione JavaScript che, dato un colore in codice esadecimale, restituisce il codice esadecimale del colore opposto, verrà chiamata in due tempi all’interno di tutto il programma:

1. nel momento in cui viene acceso il simulatore e le particelle verrano create (funzione start()) 2. nel momento il cui avverrà un passaggio di stato (funzione handleState())

Studiando il codice è stato osservato che la funzione handleState(), dedita a controllare i passaggi di stato delle particelle, veniva chiamata sempre mente il motore particellare è attivo. Ciò risulta non essere corretto, poiché il controllo sulle particelle in se, deve essere effettuato solo nelle funzioni di riscaldamento e raffreddamento (warm() e cold()), che, rispettivamente, avranno le seguenti istruzioni dentro le funzioni:

Rispetto alla versione iniziale, handleState() prende in input tutti i colori delle particelle, mentre, precedentemente, venivano direttamente letti all’interno della funzione. Questa scelta è dovuta al fatto che, quando verrà eseguito la funzione, una particella dovrà essere nel mezzo al wrapper e di un colore opposto rispetto a tutte le particelle nel wrapper. Questa scelta potrebbe far evidenziare in maniera più vivida il comportamento delle particelle.