jQuery : Système de tag d’images avec des formes personnalisables

Benjamin Longearet 14 février 2011 7
jQuery : Système de tag d’images avec des formes personnalisables
 

Personnaliser la forme des tags d’une image

Dans un précédent billet intitulé « jQuery tagger des images« , j’avais proposé une idée de conception d’un outil permettant de tagger des images. Suite à quelques remarques concernant la forme du tag géré, j’ai pensé à une autre façon de concevoir ces tags.

La propriété HTML

liée à une image permet de générer des zones tels que : CERCLE, RECTANGLE, POLYGONE. J’ai donc modifié le code précédent pour obtenir ces différentes formes.

Le plugin de sélection « imgareaselect » ne permet de gérer que la forme RECTANGLE, et je n’ai pas le temps de le modifier pour gérer les deux autres formes. J’ai donc oublié ce plugin pour cette démonstration.

Pré-requis

Le fichier HTML

Il est peu modifié par rapport au précédent billet, je vous mets la nouvelle version pour éviter de faire des allers-retours entre les deux billets.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Tagger une image!</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="css/selectarea/imgareaselect-default.css" />
<link rel="stylesheet" type="text/css" href="css/impromptu/impromptu.css" />
    <script type="text/javascript" src="js/jquery-1.4.2.min.js"></script>
    <script type="text/javascript" src="js/jquery.maphilight.js"></script>
    <script type="text/javascript" src="js/jquery-impromptu.3.0.js"></script>
    <script type="text/javascript" src="js/jquery.tooltip.js"></script>
<style type="text/css">
      body {
        background-color: #EFEFEF;
      }
      img {
        border: 0;
      }
      #tooltip{
        position:absolute;
        border:2px solid #333;
        background:orange;
        padding:2px 5px;
        color:black;
        font-weight: bold;
        display:none;
      }
    </style>
  </head>
  <body>
<h1 style="text-align:center; color: #956AAA;">Test image tag</h1>
<table>
<tr>
<td width="200px;" valign="top">
          <br/>1. Cliquer sur le boutton "Tagger!"
          <br/>2. Créer la selection
          <br/>3. Sauvegarder
          <br/>4. Survoler la zone taggée
        </td>
<td width="900px">
          <a id="imageTopLink">&amp;nbsp;</a>
          <img alt="Le mur!" id="photo" src="img/wall1.jpg" usemap="#wall1" />
        </td>
<td width="100px" valign="top" style="padding-top:20px;">
<input type="button" id="clickFinSelect" value="sauvegarder" disabled="disabled" />
<input type="button" id="clickTagCercle" value="Tagger cercle!" />
<input type="button" id="clickTagRectangle" value="Tagger Rectangle!" />
<input type="button" id="clickTagPerso" value="Tagger polygone!" />
<input type="button" id="testTag" value="Test!" />
        </td>
</tr>
</table>
<map id="wall1" name="wall1">
<area title="1" coords="696, 237, 21" shape="CIRCLE" id="areaMapGenerate-1" href="#imageTopLink">
<area title="2" coords="378, 139, 439, 249" shape="RECT" id="areaMapGenerate-2" href="#imageTopLink">
<area title="3" coords="770, 253, 807, 247, 840, 270, 857, 301, 839, 330, 788, 325, 749, 317, 741, 286, 764, 262" shape="POLY" id="areaMapGenerate-3" href="#imageTopLink">
<area title="4" coords="430, 356, 429, 342, 433, 324, 443, 315, 454, 315, 454, 327, 468, 328, 466, 313, 452, 306, 435, 306, 422, 314, 418, 330, 422, 350, 428, 361" shape="POLY" id="areaMapGenerate-4" href="#imageTopLink">
    </map>
  </body>
</html>

Juste quelques boutons de rajouter pour différencier les formes prisent en compte par la balise

de HTML.

Les plugins jQuery

jQuery.maphilight.js

L'utilisation de ce plugin ne change pas, je vous recopie donc la description de ce plugin pour mon application.

« J'ai du modifier un petit peu ce fichier pour arriver à mes fins (jquery.maphilight.js). Ce plugin permet d'afficher graphiquement au survol d'une zone de l'image un div avec un style personnalisable. Les zones à afficher sont tous simplement définies dans le

associé à l'image.

Cette balise HTML

(cf map_tag et area_tag) permet de créer des liens cliquables sur des images. Ce plugin permet donc juste de parser cette balise

et d'afficher à l'écran la zone définit dans ces balises

. »

Le fichier jquery.maphilight.js modifié

Vous trouverez ce fichier modifié sur la démo ou plus directement via ce lien.

jQuery.tooltip.js

Ce plugin permet d'afficher le "title" d'un lien de façon plus élégante que celle du navigateur. Ce plugin n'est pas modifié, vous pouvez prendre la version officielle.

jQuery.impromptu.js

Il me permet de demander à l'utilisateur de saisir le libellé du tag de façon plus élégante ! Ce plugin est non essentiel au bon fonctionnement de l'application, la méthode prompt() de JavaScript suffirai largement.

Le code jQuery

Bon le principe est simple. Il faut différencier les trois formes disponibles.

Démarche de génération des formes

Le cercle

Pour le cercle, l'utilisateur doit procurer deux informations :

  • Un click pour le centre du cercle
  • Un click pour le rayon du cercle

Le rectangle

Pour le rectangle l'utilisateur doit produire deux clicks également :

  • Un click pour un coin du rectangle
  • Un second click pour le coin opposé au premier click

Le polygone

Cas particulier, l'utilisateur a un nombre illimité de click. La procédure de fin se fera alors avec le bouton « Sauvegarder » qui s'active dès que l'on commence à dessiner un polygone.

Le code source

$().ready(function() {
      var maphilight = false;
      var idCourant = 0;
      var arrayClick = null;
      var arrayShape = new Array("CIRCLE", "RECT", "POLY");
      var circleLength;
      var startTag = 0;
      // Gestion des tags (CERCLE, RECTANGLE, POLYGONE)
      $("input#clickTagCercle").click(function() {
        startTag = 1;
        arrayClick = new Array();
      });
      $("input#clickTagRectangle").click(function() {
        startTag = 2;
        arrayClick = new Array();
      });
      $("input#clickTagPerso").click(function() {
        startTag = 3;
        arrayClick = new Array();
      });
      // Gestion des click sur l'image
      $("img#photo").live("click", function(e) {
        var coordClick = getClickPosition($(this), e);
        // Circle tag!
        if(startTag == 1) {
          if(arrayClick.length < 1) {
            arrayClick.push(coordClick);
          } else if(arrayClick.length == 1) {
            var last = arrayClick[0];
            var newX = Math.pow(Math.abs(coordClick["x"] - last["x"]), 2);
            var newY = Math.pow(Math.abs(coordClick["y"] - last["y"]), 2);
            circleLength = Math.round(Math.sqrt(newX + newY));
            validFinTag();
          }
        } else if(startTag == 2) {
          if(arrayClick.length < 1) {
            arrayClick.push(coordClick);
          } else if(arrayClick.length == 1) {
            arrayClick.push(coordClick);
            validFinTag();
          }
        } else if(startTag == 3) {
          if(arrayClick.length == 1)
            $("input#clickFinSelect").attr("disabled", "");
          arrayClick.push(coordClick);
        }
      });
      // Gestion de la sauvegarde pour le polygone
      $("input#clickFinSelect").click(function() {
        $("input#clickFinSelect").attr("disabled", "disabled");
        validFinTag();
      })
      // Récupère la position du click par rapport à l'image
      function getClickPosition(object, event) {
        var returnObject = Array();
        if(object.css('position') == "absolute") {
          var imagePosition = object.parent().position();
          returnObject["x"] = Math.round(event.pageX - imagePosition.left);
          returnObject["y"] = Math.round(event.pageY - imagePosition.top);
        } else {
          var imagePosition = object.position();
          returnObject["x"] = Math.round(event.pageX - imagePosition.left);
          returnObject["y"] = Math.round(event.pageY - imagePosition.top);
        }
        return returnObject;
      }
      // Valide et sauvegarde le tag
      function validFinTag() {
        idCourant++;
        // Méthode callback après la validation du prompt
        function mycallbackform(v,m,f){
          var coords;
          // Cercle
          if(startTag == 1)
            coords = arrayClick[0]["x"]+', '+arrayClick[0]["y"]+', '+circleLength;
          // Rectangle
          if(startTag == 2)
            coords = arrayClick[0]["x"]+', '+arrayClick[0]["y"]+', '+arrayClick[1]["x"]+', '+arrayClick[1]["y"];
          // Polygon
          if(startTag == 3) {
            coords = "";
            for(i=0,j=arrayClick.length;i<j;i++) {
              if(i>=1)
                coords = coords + ', ';
              coords = coords+arrayClick[i]["x"]+', '+arrayClick[i]["y"];
            }
          }
          // Récupère le bon libellé pour la forme courante
          var shapeId = startTag - 1;
          var shape = arrayShape[shapeId];
          // Ajoute la nouvelle form à la
<map ..>
          $("#wall1").append('
<area href="#imageTopLink"'+
            'id="areaMapGenerate-'+idCourant+
            '" shape="'+shape+
            '" coords="'+coords+
            '" title="'+f.alertName+'" />');
          // Actualise le maphilight
          $('.map').maphilight();
          // Actualise les tooltips
          tooltip();
          // Réinitialise les variables globales
          arrayClick = new Array();
          circleLength = 0;
        }
        // Texte de la fenêtre prompt
        var txt = 'Le nom de la personne à tagger:'+
          '
<input type="text" '+
          'id="alertName" '+
          'style="width:300px;" '+
          'name="alertName" '+
          'value="" />';
        $.prompt(txt,{
          callback: mycallbackform,
          buttons: { Ok: true },
          focus: 1
        });
      }
			//Gestion de l'affichage ou non du maphilight
      $("#testTag").click(function() {
        maphilight = !maphilight;
        $('.map').maphilight({alwaysOn:maphilight});
      });
      // Initialisation
      $('.map').maphilight();
      tooltip();
    });

Aller plus loin

Cette mini-demo n'est pas optimisé, sécurisé et blablabla et blablabla. C'est juste à titre d'exemple.

Il serait effectivement judicieux que l'utilisateur puisse visualiser les clicks en direct, voir la forme dynamiquement modifier.

Il faudrait également rajouter la modification de ces formes.

Bref faite travailler votre imagination sans oublier de rester les pieds sur terre et surtout sans oublier qu'un utilisateur veut faire un maximum de chose en un minimum d'action =D

Bon dév ! :D

image_taggable_multiforme
Titre : image_taggable_multiforme
Légende :
Nom du fichier : image_taggable_multiforme.zip
Taille : 257 Ko

7 Commentaires »

  1. brizoo 1 mars 2012 au 2 h 09 min - Reply

    Hello ! Tu ne met pas a disposition le Plugin jQuery “maphilight” ? Vu qu’il est legeremenet modifié ca aurait pu etre bien ! Merci en tout cas pour ce tuto c’est vraiment pas mal ! Dernière question, une piste pour afficher le polygone pendant qu’on est entrain de le créer ? je ne vois pas comment faire ! Merci

    • Benjamin Longearet
      Benjamin Longearet 1 mars 2012 au 8 h 44 min - Reply

      Salut brizoo,

      Tu as raison, je vais le mettre à disposition.
      Pour dessiner en temps réel, je ne vois qu’une seule solution : L’utilisation d’un canvas.
      L’idée est intéressante, si j’ai le temps j’essayerai de faire une démo avec un canvas.

  2. DALAL 8 mars 2012 au 19 h 40 min - Reply

    Salut Benjamin, merci pour ce tuto qui ma beaucoup aidé je l’ai modifier pour arrivé à mes fins, peut tu m’aider a utiliser les canvas !
    Merci ^^

    • Benjamin Longearet
      Benjamin Longearet 13 mars 2012 au 12 h 06 min - Reply

      Salut Dalal,
      Si tu as quelques questions, tu peux m’envoyer un mail.
      Je n’ai pas beaucoup de temps, mais j’essayerai d’y répondre.
      Bon dév!

  3. DALAL 20 avril 2012 au 18 h 09 min - Reply

    Salut tous le monde, esque quelqu’un a pu fair: visualiser les clicks en direct
    la modification des formes
    Merci :)

  4. LeDanD 3 mai 2012 au 18 h 26 min - Reply

    Bonjour – Très intéressant.
    J’ai télé(dé)chargé les sources à plusieurs reprises, mais le fichier zip semble corrompu: ni Windows ni un utilitaire d’extraction (7-zip) n’arrivent à le lire … Pourriez-vous vérifier ?
    Merci d’avance.

    • Benjamin Longearet
      Benjamin Longearet 3 mai 2012 au 19 h 24 min - Reply

      Salut LeDanD!

      Merci pour le commentaire, j’ai remis à jours le fichier zip. Dis moi si cela fonctionne maintenant!

      Bonne soirée.

Laissez un message »