Gestione della rotella del mouse in JavaScript
sabato 26 agosto 2006Piccola precisazione:
Il codice qui utilizzato è una rielaborazione e traduzione di quanto pubblicato da Adomas Paltanavicius qui.
Molto gentilmente Adomas ha linkato nel suo sito questo riadattamento.
Problema
Un buon programmatore di solito tende a chiedersi: "E che cacchio, con tutte ste figherie che ci sono oggi (AJAX, Ruby, Script.aculo.us, ecc...) perché non posso usare (roba a caso) nella mia fichissima Web Application?" Non so se voi ve lo chiediate ogni tanto, io sì, anche abbastanza spesso...
La roba a caso di oggi si chiama "Rotella del mouse"
Soluzione
Un tipo lituano ha trovato la soluzione, (già elaborata dal buon Google in Google Maps) e io sono qui a tradurla in italiano e a documentarla un pelo per chiunque abbia voglia di usarla.
In Pratica
La rotella del mouse in qualsiasi browser di solito permette lo scrolling delle pagine... Giusto? Ebbene, la suddetta rotella genera un evento all'interno della finestra, e questo evento può essere letto via JavaScript, con qualche aggiustatina, a seconda del browser utilizzato.
Il valore letto non è numerico, ma si tratta di un "delta" (ovvero una variazione) rispetto al valore precedente. Quindi può essere positivo o negativo. Un immagine, come sempre è meglio di 1000 parole...

Vediamo ora come viene letto l'evento via JavaScript:
// INIZIALIZZAZIONE if (window.addEventListener) // MOZILLA window.addEventListener('DOMMouseScroll', wheel, false); // IE / OPERA window.onmousewheel = document.onmousewheel = wheel;
Queste due righe hanno generato il listener per l'evento "movimento della rotella del mouse". Al verificarsi dell'evento viene richiamata la funzione wheel() che è poi la funzione che fa la "magia"
// GESTORE EVENTO "MOVIMENTO ROTELLA" function wheel(event) { // Variabile che conterrà la variazione di movimento var delta = 0; // INTERNET EXPLORER if (!event) event = window.event; // INTERNET EXPLORER E OPERA if (event.wheelDelta) { delta = event.wheelDelta/120; // IN OPERA 9 IL SEGNO E' INVERTITO if (window.opera) delta = -delta; } // MOZILLA - LUNGA VITA A MOZILLA else if (event.detail) { // DELTA INVERTITO E MULTIPLO DI 3 delta = -event.detail / 3; } // SE IL DELTA E' DIVERSO DA ZERO ESEGUE LA FUNZIONE HANDLE if (delta) handle(delta); // BLOCCA SCROLLING IN PAGINE LUNGHE... if (event.preventDefault) event.preventDefault(); // RITORNA FALSO event.returnValue = false; }
Che abbiamo fatto? Praticamente abbiamo normalizzato i differenti valori restituiti dai diversi browser in modo da ottenere 1 o -1.
Il valore così ottenuto viene passato alla funzione handle() che conterrà le istruzioni da eseguire. Nel nostro caso l'aumentare o il diminuire la dimensione di un testo.
// GESTIONE EVENTO (RIDIMENSIONAMENTO TESTO) function handle(delta) { // Dimensioni testo var dimensione; if (delta < 0) { // Zoom OUT dimensione = parseInt(document.getElementById("testo").style.fontSize) + 2; document.getElementById("testo").style.fontSize = dimensione + "px"; } else { // Zoom IN dimensione = parseInt(document.getElementById("testo").style.fontSize) - 2; document.getElementById("testo").style.fontSize = dimensione + "px"; } }
Tutto qua. Niente di più facile. Un esempio, liberamente scaricabile e riadattabile è disponibile qui. Su suggerimento di Adomas ecco un image resizer.
E le pagine lunghe?
Bella domanda. Se usate questo script in una pagina che scrolla, la rotella non permetterà lo scrolling della pagina...
Per gli utenti Firefox
Noi non abbiamo bisogno di questo script di esempio che ho creato... Premendo CTRL mentre si muove la rotella del mouse viene aumentata automaticamente la dimensione del carattere.
Può tornare utile se vogliamo fornire la stessa funzionalità ai "poveracci" che usano Internet Explorer
Compatibilità
Funziona su Firefox 1+, Internet Explorer 5+, Opera, Safari, ecc...
Possibili usi
Zoom di testo, zoom di immagini, scrolling di testo, riordino di liste e qualsiasi idea malsana vi possa venire in mente...
UPDATE!
Andrea Giammarchi ha prodotto un esempio che risolve il problema dello scrolling della pagina. Riporto parte della sua email come spiegazione:
L'evento onmousewheel non ha nulla di diverso da onclick, onmouseover e compagnia bella, questo significa che non è un evento window o document ma un evento qualunque di un Node del DOM (che sia preso per id o tag ha poca importanza purchè sia un elemento del DOM).
Ergo la mia funzione sfrutta onmouseover per attivare su quel solo elemento onmousewheel per poi toglierlo in onmouseout da quell'elemento, quindi non vincola assolutamente lo scroll della pagna fuori dall'elemento
![]()
Le potenzialità sono quelle da te descritte nel tuo post del blog, solo che il vincolo della window non esiste ed il fatto che sia un evento compatibile solo con browsers aggiornati gli permette di sfruttare addEventListener o attachEvent per l'onmouseover senza vincolare altri eventuali eventi del DOM sullo stesso elemento (più onmouseover o onmouseout sullo stesso nodo senza problemi.
Trovate il sorgente qui e un'implementazione davvero funzionale qua. Manca quo, ma ci stiamo organizzando.
In alternativa puoi abbonarti alla newsletter, riceverai un'email ogni volta che verrà pubblicato un nuovo post. Il tuo indirizzo email sarà gestito da Feedburner.











(5 voti, media: 4,60)
30 agosto 2006 alle 16:29
[...] Visto che tra cani e porci molti (me compreso) ci si trovano bene, oggi vediamo, partendo dal solito principio del “Perché non posso usare (roba a caso) nella mia fichissima Web Application?” citato qui, come poter anche noi utilizzare tutta la potenza di Google Maps, creando da zero una mappa in cui poter inserire dei markers a nostro piacimento. [...]
12 settembre 2006 alle 17:15
grazie per la traduzione, mi permetto di postare anche qui la mia soluzione riadattata che non ha problemi di blocco scroll, spero sia utile.
esempio: http://www.devpro.it/examples/onmousewheel.html
sorgente: http://www.devpro.it/javascript_id_134.html
Saluti
12 settembre 2006 alle 20:08
Fammi capire…
Praticamente “ascolti” l’evento solo se il mouse è su quella determinata DIV che nel tuo caso ha id “test”.
Davvero notevole. Posso inserire i riferimenti al tuo esempio e la spiegazione nel post???
12 settembre 2006 alle 22:42
ops …. ho visto dopo la tua risposta, ti ho scritto tutto per email comunque la risposta è si (ma leggi la mail se hai tempo)
Ciao
13 settembre 2006 alle 09:14
@Andrea Giammarchi
Fatto! Se ci sono novità fammi un fischio per email
13 settembre 2006 alle 09:35
Una novità c’è … ho aggiunto dipendenze alla funzione che ora è fatta di pochissime linee di codice.
Siccome il “trick” per l’addEventListener è usato e riusato in non so quante funzioni ho pensato di normalizzare il tutto tramite un oggetto, chiamato DOM (che fantasia …), in grado di aggiungere o rimuovere listener di eventi (uno o più) al fine di non dover “ingigantire” un probabile insieme di scripts con lo stesso controllo per ogni evento che si vuole aggiungere (un pò come hanno fatto in Dojo ma …. hei, Dojo pesa di suo sui 100Kb pacchettizzata … !!!).
Questo oggetto DOM (http://www.devpro.it/code/135.html) per ora ha solo addEventListener e removeEventListener ma ha la peculiarità di poter essere sfruttato da IE4 a tutti i browsers attuali per gli eventi più comuni o per, in questo caso, l’evento wheel.
L’oggetto DOM a sua volta sfrutta la JSL (http://www.devpro.it/JSL/), la mia “low-level-lib” preferita, capace di normalizzare tutti i browsers, sempre a partire da IE4, per usare JavaScript 1.6 standard al fine di poter sfruttare senza preoccuparsi di niente prototipi di array come some o filter o altri metodi standard di “oggetti primitivi” presenti solo in JS 1.6, utilissimi per tanti motivi ed in grado di farci creare altre librerie sempre leggere e soprattutto senza preoccuparsi di riscrivere ogni volta “gli stessi tricks” per ogni funzione che vorrebbe sfruttare questa o quella proprietà/metodo.
Altra caratteristica della JSL è che un domani, quando il 99% dei browsers supporterà almeno JS 1.6 in modo standard, potrà essere esclusa dalla pagina senza problemi, risparmiando i suoi 7Kb di peso, poco influenti se si considerano le potenzialità, ma mai irrisori quando si vuole cercare di risparmiare banda.
Questo, per concludere, credo sia il “quo” che mancava alla mia soluzione, rinnovo i ringraziamenti per questa traduzione e porgo i saluti
13 settembre 2006 alle 09:52
18 settembre 2006 alle 17:35
Una novità ? Sono idiota
Mi sono incartato con il discorso del blocco che di fatto non esisteva, e siccome onmousewheel è un evento, come ho già detto, di un Elemento e siccome un elemento richiama questo evento solo se il mouse agisce sullo stesso, ho rimosso tutto dalla funzione che ora è più semplice e si spera efficiente che mai
ne parlo nel mio blog:
http://webreflection.blogspot.com/2006/09/portable-and-rewrote-onmousewheel.html
qui il nuovo esempio:
http://www.devpro.it/examples/onmousewheel.html
19 ottobre 2006 alle 13:19
[...] JS Mouse Wheel – ITA [...]
10 gennaio 2007 alle 12:06
utilissima e bellissima implementazione!
l’ho usata nel mio piccolo portfolio e funziona benissimo.
10 gennaio 2007 alle 12:10
@pinit
Che bello! Sembra quasi Flash
19 gennaio 2007 alle 18:41
[...] Italian translation with live demonstration, by Francesco Napoletano. [...]
29 agosto 2007 alle 12:37
Ciao, sono Claudio spero leggerai e saprai aiutarmi.
Da tempo oramai ho un unico e solo problema con l’amato Firefox, non appena lo installo senza che faccio nulla non mi funziona la rotellina del mouse, e non posso neppure scorrere le pagine. Posso farlo solo “manualmente”.
Solo tempo fa riuscii a risolvere, perchè lo disinstallai e reinstallai, ma poi ho dovuto reinstallarlo nuovamente ultimamente e il problema si è ripresentato.
Quindi a questo punto credo che il problema sia proprio all’interno della cartella firefox.
Aspetto una tua risposta, anche via e.mail.
E W Firefox
29 agosto 2007 alle 17:15
Purtroppo non saprei come aiutarti… Prova a chiedere sui forum di mozilla italia
29 agosto 2007 alle 17:29
piccolo update al post: pare che dalla realease 9.20 di Opera il valore dell’handle non sia più invertito, infatti ora il delta viene gestito come negli altri browsers
29 agosto 2007 alle 20:20
OK, grazie comunque.