JQuery – Réaliser facilement un zoom personnalisé

Tuto JQuery : créer à partir d’une simple image dans le DOM une div qui présente une zone agrandie de cette image, de telle sorte que l’on puisse se déplacer sur l’image zoomée simplement en bougeant la souris.
Florent TRIPIERMis à jour le 1 Juil 2014

Pourquoi réinventer la roue ?

JQuery a rendu facile le recours au JavaScriptLangage de scripting orienté objet dans les applications web. Un ensemble de pratiques courantes, auparavant assez techniques, sont désormais accessibles, même aux débutants : faire des requêtes Ajax, accéder à des éléments du DOM en utilisant des sélecteurs CSSFeuilles de style qui permettent de mettre en forme des pages web., binder des actions sur des événements

JQuery a aussi facilité le développement déléments plus complexes comme des champs dautocomplétion, des fenêtres de dialogue ou des color pickers. Pour ces fonctionnalités plus complexes, il existe un grand nombre de plugins. Mais ces plugins sont souvent difficiles à intégrer et se veulent très génériques alors que lon a souvent un besoin très précis (et que lon souhaite limiter la quantité de JavaScript par souci évident de performance). Or certaines fonctionnalités pour lesquelles un grand nombre de plugins existent ne sont en fait pas très complexes à implémenter soi-même. Ici, nous allons voir comment on peut développer facilement et en peu de lignes un zoom.

Principe

Le but est de créer à partir dune simple image dans le DOM une div qui présente une zone agrandie de cette image, de telle sorte que lon puisse se déplacer sur limage zoomée simplement en bougeant la souris.

De nombreuses présentations sont possibles : un zoom qui se déplace par dessus limage, ou bien situé sur le côté, ou bien qui remplace limage un zoom carré, rond Dans tous les cas le principe est le même, il sera donc facile de lui donner lapparence que lon veut et de le positionner où on veut.

Ici, nous allons réaliser un zoom rond qui suivra le curseur de la souris dès lors quelle sera au-dessus de limage de départ. Les étapes sont donc :

  • initialiser le zoom : créer les structures dans le DOM qui permettront dafficher le zoom
  • binder les événements : faire en sorte dafficher le zoom lorsque la souris entre sur limage, de le cacher quand elle en sort, et de le positionner quand elle bouge
  • positionner le zoom : afficher la bonne zone de limage zoomée positionner la div du zoom par dessus limage
  • mettre en place le style CSS qui permettra un rendu agréable

Version de JQuery

Les versions 2.x de JQuery sont plus légères mais présentent le fâcheux inconvénient de ne pas être compatible avec les versions dInternet Explorer antérieures à 9. Or IE 8 représente encore 5% de part de marché en février 2014, pourcentage dinternautes dont nous ne voulons pas nous priver. Pensez bien en revanche lorsque vous téléchargez la dernière version 1.x sur le site de JQuery à prendre le format .min.js, qui est compressé.

Initialiser le zoom

Le but est dobtenir à partir dune image un agrandissement de cette image contenu dans une div. La « partie div » de la méthode ne pose pas de problème, la partie image un peu plus. Deux cas de figure se présentent :

  • vous avez la possibilité à partir de limage source dextrapoler une URL vers un agrandissement de cette image : cest le meilleur cas de figure. Vous avez alors deux possibilités daffichage :
    • vous affichez les deux images (loriginal et lagrandissement) en taille réelle : il faut alors veiller à ne pas avoir un rapport de taille trop important entre des deux images et stocker le ratio dans une variable ;
    • vous imposez une taille à votre agrandissement selon un ratio prédéfini judicieusement (2 par exemple), en prenant le risque de réduire beaucoup ou agrandir excessivement votre image ;
  • vous ne disposez que de votre image source : il faut alors la dupliquer et appliquer à la copie une taille relative à celle de loriginal.

Nous allons nous positionner dans ce dernier cas : il suffira de quelques modifications pour mettre en place une des deux autre possibilités. Imaginons que les images sur lesquelles on souhaite mettre en place notre zoom portent la classe CSS « zoomable ». On peut donc imaginer un code tel que :

$(’img.zoomable’).each(function(){
   var zoombox=$(’

<div id="’ + $(this).attr(’id’) + ’zoombox" class="zoombox" >
  
</div>’).insertAfter($(this));      
   $(this).clone().attr(’id’, $(this).attr(’id’) + ’zoom’).attr(’width’, $(this).attr(’width’)*2).appendTo(zoombox); 
});

Ici, on sélectionne toutes les images à zoomer, puis on boucle sur le résultat : pour chaque image trouvée, on crée une div quon met juste après limage originale, et on copie limage dans la div. On paramètre la largeur de la copie à deux fois celle de loriginale. De plus, la div et limage copiée ont chacune un id dérivé de celui de limage source, de façon à pouvoir y accéder à partir de limage source.

Binder les événements

Maintenant que nous avons construit la structure HTMLHTML (HyperText Markup Language) est un langage permettant de décrire le découpage d'une page web. de notre zoom, il faut faire en sorte de lafficher seulement lorsque la souris passe au-dessus, et de le positionner pour quil suive celle-ci. Les événements quil faut intercepter sont donc :

  • lentrée de la souris sur limage
  • le mouvement de la souris sur limage
  • la sortie de la souris de limage

Si lon continue à partir du code précédent, on peut donc écrire le code suivant :

$(’img.zoomable’).each(function(){
   var zoombox=$(’

<div id="’ + $(this).attr(’id’) + ’zoombox" class="zoombox" >
  
</div>’).insertAfter($(this));   
   $(this).clone().attr(’id’, $(this).attr(’id’) + ’zoom’).attr(’width’, $(this).attr(’width’)*2).appendTo(zoombox); bindZoom($(this)); }); 
function bindZoom(img) { 
   img.bind(’mouseenter mouseover’, function(e){ 
      $(’#’ + img.attr(’id’) + ’zoombox’).css(’display’,’block’); 
      positionZoom(e,img); 
   }); 
   img.bind(’mouseleave’, function(e){ 
      $(’#’ + img.attr(’id’) + ’zoombox’).css(’display’,’none’); 
   }); 
   img.bind(’mousemove’, function(e){ 
      positionZoom(e,img); 
   }); 
}

Ici, pour chaque image zoomable, on crée le zoom comme vu précédemment, puis on appelle une fonction qui regroupe les bindings. Dans cette fonction, on retrouve les 3 événements annoncés :

  • mouseenter, mouseover : on affiche la « boîte » du zoom et on le positionne ;
  • mouseleave : on cache la « boîte » du zoom ;
  • mousemove : on repositionne le zoom.

Le positionnement du zoom fait toujours appel à une fonction positionZoom que nous allons voir à présent.

Positionner le zoom

Cette partie peut apparaître comme la plus compliquée, mais ne lest pas tant que ça : il sagit simplement de se déplacer dans un repère orthonormé en deux dimensions. Il faut donc calculer une position x et une position y. Deux options se présentent :

  • calculer les positions absolues par rapport à la page ;
  • calculer une position relative par rapport à limage : il faut donc positionner limage dans un conteneur (une div) par rapport auquel on puisse se positionner.

Nous allons retenir cette deuxième proposition. On peut donc obtenir le code suivant :

function positionZoom(e,img) {
   var offset=img.offset();
   var zoombox=$(’#’ + img.attr(’id’) + ’zoombox’);
   zoombox.css(’left’, (e.pageX-offset.left+30)+’px’);
   zoombox.css(’top’, (e.pageY-offset.top-75)+’px’);
   var zoom=$(’#’ + img.attr(’id’) + ’zoom’);
   zoom.css(’left’, ((e.pageX-offset.left-37.5)*-2)+’px’);
   zoom.css(’top’, ((e.pageY-offset.top-37.5)*-2)+’px’);
}

Ici, on récupère loffset de limage par rapport à la page. Puis on positionne la boîte en lui donnant un x qui loffset de la souris par rapport à la page moins celui de limage, ce qui nous donne loffset de la souris par rapport à limage. De plus, on décale la boîte de 30px vers la gauche pour la détacher du curseur de la souris, et de 75px vers le haut pour la centrer verticalement par rapport au curseur (on a une boîte de 150px de côté).

Pour positionner limage zoomée, cest un peu plus complexe. Dabord le mouvement est inversé : si je bouge ma souris vers la droite, alors je dois décaler mon image zoomée vers la gauche. Pourquoi ? Dans un cas, la zone ciblée bouge avec ma souris. Dans lautre, la zone ciblée est fixe : cest le centre de ma boîte. Donc pour que le centre de ma boîte coïncide avec un point plus à droite sur limage, je dois déplacer mon image vers la gauche. Même raisonnement pour lapproche verticale.

Ensuite, il faut tenir compte du changement déchelle : lorsque je me déplace de 100px sur mon image originale, je dois décaler mon zoom de 100 fois mon ratio, ici 100*2px. De plus, mon zoom ne fait pas la taille dun px, et jai fait en sorte que le point ciblé par mon curseur corresponde au centre de mon zoom, et non pas au coin supérieur gauche. Je dois donc en tenir compte dans mon calcul doffset.

Au final, on soustrait loffset de limage à celui de la page comme précédemment, et lon soustrait encore la taille de la boîte divisée par le ratio. Ici jai une boîte de 150px et un ratio de 2 : je soustrais 37,5px. Jobtiens une position relative du curseur sur limage originale. Pour avoir loffset final sur le zoom, je multiplie par le ratio, et jinverse le signe (ou je multiplie par -1) pour tenir compte du mouvement inversé que jai expliqué précédemment. Et le tour est joué !

Mise en forme CSS

Le style sur un composant de ce genre nest pas uniquement décoratif. Il permet également le positionnement absolu ou relatif des éléments les uns par rapport aux autres. Ici, nous nous contenterons de ce qui est nécessaire à la réalisation du zoom et de la mise en forme de la boîte de zoom.

Nous allons considérer que nous travaillons sur le code HTML suivant :

  <img id="monimage" class="zoomable" src="monimage.jpg" alt="" width="512" />
  
</div>

Nous avons ici quelque chose de simpliste : une image dans une div. La div permettra de servir de repère pour le positionnement relatif du zoom. Je propose le code CSS suivant :

div#container {
   position: relative;
   width: 1000px;
   margin: auto;
}
img.zoomable{
   cursor: crosshair;
}
div[id$="zoombox"] {
   position: absolute;
   overflow: hidden;
   height: 150px;
   width: 150px;
   border: 2px solid #E5E5E5;
   background-color: #FFFFFF;
   box-shadow: 1px 1px 12px #999999;
   border-radius: 75px;
   -moz-border-radius: 75px;
   -webkit-border-radius: 75px;
}
img[id$="zoom"] {
   position: absolute;
}

Il y a quatre groupes de propriétés CSS :

  • le premier concerne la div qui englobe limage originale : lélément à retenir est le positionnement relatif. Cest grâce à cela que le positionnement absolu de la boîte de zoom se fera relativement à cette div et non à la page entière ;
  • le deuxième est esthétique : il concerne lapparence du pointeur au-dessus de limage ;
  • le troisième concerne la boite : les éléments obligatoires sont le positionnement absolu, loverflow, qui permet de masquer les parties de limage zoomée qui sont en-dehors de la div, et la width et la height. Le reste permet de mettre en forme la boîte : ce style est un exemple, on peut le décliner à linfini ;
  • le quatrième concerne limage zoomée et son positionnement.

Il ne reste quà assembler tous ces éléments pour mettre en oeuvre notre zoom.

Exemple

Voici un petit code presque auto-suffisant pour afficher notre zoom. Il faut toutefois :

  • mettre une version de JQuery dans le même répertoire, et si ce nest pas celle paramétrée dans le head modifier ce dernier ;
  • mettre une image dans le même répertoire, et mettre son nom dans la balise img. Pour un rendu optimal, utilisez une image de 1024px (doù le css width= 512&Prime; ), ou bien modifiez la width de façon à ce quelle soit la moitié de la taille réelle.
  • mettez le code ci-dessous dans un fichier HTML et affichez-le.
<div id="container">
  <img id="monimage" src="monimage.jpg" width="512" class="zoomable" />
</div>

Conclusion

La longueur de cet article peut faire penser que la tâche est plus ardue que le titre ne le laisse supposer, mais cest en définitive effectivement assez simple.

Pour aller plus loin, il y a mille façons daméliorer et/ou de personnaliser ce zoom :

  • afficher le zoom sur le côté
  • modifier sa forme / son apparence
  • utiliser réellement 2 images de définitions différentes
  • afficher le zoom à la place de limage de départ