IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Contribuez Discussion :

Rendre une <area> responsive


Sujet :

Contribuez

  1. #1
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    16 939
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 16 939
    Points : 44 112
    Points
    44 112
    Par défaut Rendre une <area> responsive

    Une récente discussion sur le forum a réveillé en moi ce qui va suivre ...

    Le but est de rendre les éléments HTML <area>, d'une <map>, responsive dynamiquement en s'aidant de JavaScript.

    Constat
    Il peut nous arriver d'avoir besoin qu'une image, sur laquelle une <map> est associée, soit responsive.

    On sait que l'attribut coords, des <area>, défini les coordonnées de la forme décrite par l'attribut shape et permet ainsi de positionner et dimensionner les zones interactives d'une image.

    Seulement voilà les valeurs sont exprimées en pixels CSS et ne peuvent plus forcément s'appliquer si l'image, dont elles représentent les zones d'intérêt, est elle « responsive ».

    Ce que l'on souhaite obtenir
    Des zones d'intérêt toujours au même endroit par rapport à l'image initiale.

    • Image dimensions 600 x 336
    Nom : sid-600x336.png
Affichages : 199
Taille : 59,8 Ko

    • Image dimensions 400 x 224
    Nom : sid-400x224.png
Affichages : 183
Taille : 29,6 Ko

    • Image dimensions 200 x 112
    Nom : sid-200x112.png
Affichages : 179
Taille : 9,9 Ko

    La solution est donc de recalculer ces coordonnées dynamiquement en fonction de la taille de l'image référente.

    Nota : Il faut que les zones soient définies par rapport à l'image originale non redimensionnée pour que cela ait de l’intérêt. Dans l'exemple présenté, la <map> est calculée, volontairement, sur une image surdimensionnée de 1920 x 1080.


    Code de la fonction qui fait ça
    Code JavaScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    /**
     * recalcule les coordonnées suivant les dimensions de l'image référente
     * @param {(null|string)} selector - rien ou sélecteur CSS de l'image ciblée.
     * @example responsiveArea('[usemap="#name-map"]');
     */
    function responsiveArea(selector) {
      selector = selector || "[usemap]";
      const elemImage = document.querySelectorAll(selector);
      elemImage.forEach((img) => {
        // get dimension image
        const imgW = img.naturalWidth;
        const imgH = img.naturalHeight;
        const nomMap = img.getAttribute("usemap");
        // image non encore chargée
        if (!(imgW * imgH)) {
          img.addEventListener("load", () => responsiveArea(`[usemap="${nomMap}"]`));
        }
        // image chargée
        else {
          // récup. data image
          const rapportX = img.width / imgW;
          const rapportY = img.height / imgH;
          // get la map associée
          const elemMap = document.querySelector(`[name="${nomMap.replace("#","")}"]`);
          // quitte si non requis
          if (elemMap.hasAttribute("noresize")) return;
          // get les area enfants
          const elemArea = elemMap.querySelectorAll("area");
          // traitement des area
          elemArea.forEach((area) => {
            const shape = area.getAttribute("shape");
            const originalCoords = area.getAttribute("originalcoords")?.split(",");
            const coords = originalCoords || area.getAttribute("coords")?.split(",");
            // sauve données initiales
            if (!originalCoords) {
              area.setAttribute("originalcoords", coords?.join(","));
            }
            // Attention : pas de test fait sur la validité de l'attribut coords
            // https://html.spec.whatwg.org/multipage/image-maps.html#attr-area-coords
            const newCoords = [];
            switch (shape) {
              case "rect":
              case "poly":
                for (let i = 0; i < coords.length; i += 2) {
                  newCoords.push(+coords[i] * rapportX, +coords[i + 1] * rapportY);
                }
                break;
              case "circle":
                newCoords.push(+coords[0] * rapportX, +coords[1] * rapportY, +coords[2] * rapportX);
                break;
              default:
            }
            // affectation
            area.setAttribute("coords", newCoords.join(","));
            // on previent à toutes fins utiles
            area.dispatchEvent(new Event("resize"));
          });
          // demande redim auto
          if (!img._observer) {
            const objObserve = new ResizeObserver(() => {
              clearTimeout(img._innerTimer);
              img._innerTimer = setTimeout(() => responsiveArea(`[usemap="${nomMap}"]`), 100);
            });
            objObserve.observe(img);
            img._observer = true;
          }
        }
      });
    }


    Démo en ligne
    Pour voir celle-ci en action je vous invite à regarder la page en ligne :
    Rendre une <area> responsive


    N’hésitez pas à poster vos remarques.

  2. #2
    Membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2018
    Messages
    166
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2018
    Messages : 166
    Points : 61
    Points
    61
    Par défaut
    Bonjour NoSmoking,

    le jeu que je souhaite faire est utilisable en l'état sur mon PC (même si non fini), mais évidemment quand je change de PC, l'affichage n'est plus le même et donc les area ne sont plus au bon endroit.

    J'ai essayé 2 méthodes :
    - partir du code du jeu et essayer d'intégrer le code que tu proposes ici, mais évidemment ça ne fonctionne pas. Car si j'ai bien compris, tu utilises une fonction Demo.updateOverlay(area.dataset.id, shape, newCoords); pour l'affichage et comme je ne l'ai pas dans mon code, cela ne change absolument rien. Et je n'arrive pas à la définir, bien évidemment.
    - partir du code complet trouvé dans la page que tu donnes et essayer d'intégrer les nouvelles fonctions pour mon jeu (affichage du score, suppression du click, prompt, cercle si la réponse est bonne...). Mais là aussi, je me confronte à un problème. J'ai essayé de supprimer l'écouteur après avoir cliqué dans une area pour commencer, impossible.

    Je préfèrerais utiliser la deuxième méthode, cela me permettrait d'intégrer les dialog que tu as mis en place (la solution déjà vue dans un autre sujet ne me convenant pas)
    Par quoi dois-je commencer? Dois-je tout reprendre depuis le début (création de la boite de dialogue-question)?

  3. #3
    Expert confirmé
    Avatar de Doksuri
    Profil pro
    Développeur Web
    Inscrit en
    Juin 2006
    Messages
    2 450
    Détails du profil
    Informations personnelles :
    Âge : 54
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 450
    Points : 4 600
    Points
    4 600
    Par défaut
    avec les canvas, c'est pas plus simple ?
    y-a-il une raison particuliere pour utiliser les area ?
    La forme des pyramides prouve que l'Homme a toujours tendance a en faire de moins en moins.

    Venez discuter sur le Chat de Développez !

  4. #4
    Membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2018
    Messages
    166
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2018
    Messages : 166
    Points : 61
    Points
    61
    Par défaut
    Je n'ai jamais utilisé canvas et mon objectif est de rendre ce jeu responsive

  5. #5
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    16 939
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 16 939
    Points : 44 112
    Points
    44 112
    Par défaut
    Citation Envoyé par bahh66
    le jeu que je souhaite faire est utilisable en l'état sur mon PC (même si non fini), mais évidemment quand je change de PC, l'affichage n'est plus le même et donc les area ne sont plus au bon endroit.
    Rien de surprenant il me semble t'en avoir parlé et c'est en cela que la fonction présentée peut t'aider !



    J'ai essayé 2 méthodes :
    - partir du code du jeu et essayer d'intégrer le code que tu proposes ici, mais évidemment ça ne fonctionne pas. Car si j'ai bien compris, tu utilises une fonction Demo.updateOverlay(area.dataset.id, shape, newCoords); pour l'affichage et comme je ne l'ai pas dans mon code, cela ne change absolument rien. Et je n'arrive pas à la définir, bien évidemment.
    Comme on pourrait s'en douter, via le préfixe Demo, elle ne sert que pour la démo, pour visualiser les différentes zones suivant le dimensionnement, et tu n'es pas obligé de l'utiliser même si il me semble que cela pourrait être un plus pour visualiser les zones lorsque tu cliques sur l'image radar.

    Pour voir à quoi elle ressemble il te suffit d'afficher le code source de la page via les touches Ctrl + U



    J'ai essayé de supprimer l'écouteur après avoir cliqué dans une area pour commencer, impossible.
    Le plus simple est de supprimer purement et simplement l'élément <area> sans rien faire d'autre. Tout ce qui le concerne disparaitra.



    Je préfèrerais utiliser la deuxième méthode, cela me permettrait d'intégrer les dialog que tu as mis en place (la solution déjà vue dans un autre sujet ne me convenant pas)
    Par quoi dois-je commencer? Dois-je tout reprendre depuis le début (création de la boite de dialogue-question)?
    Le cosmétique est à mettre en place en final mais là la gestion des alert, confirm et prompt est plus délicate et il est impossible de remplacer complètement les boîtes de dialogue JavaScript avec des fonctionnalités identiques.



    Citation Envoyé par Doksuri
    avec les canvas, c'est pas plus simple ?
    Plus simple peut-être pas, la gestion des événements sur un <canvas> est un peu plus délicate.
    Elle reste néanmoins réalisable en utilisant la méthode isPointInPath() pour détecter si un point cliqué du <canvas> est contenu dans un élément Path2D.

  6. #6
    Membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2018
    Messages
    166
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2018
    Messages : 166
    Points : 61
    Points
    61
    Par défaut
    Comme on pourrait s'en douter, via le préfixe Demo, elle ne sert que pour la démo, pour visualiser les différentes zones suivant le dimensionnement, et tu n'es pas obligé de l'utiliser même si il me semble que cela pourrait être un plus pour visualiser les zones lorsque tu cliques sur l'image radar.
    J'avais compris, mais comme je ne sais pas enlevé le préfixe Demo, je me suis dit que j'allais le conserver et le rajouter aux fonctions que j'ajouterai du coup.

    Pour voir à quoi elle ressemble il te suffit d'afficher le code source de la page via les touches Ctrl + U
    Ca j'avais fait et ça donne ça maintenant.

    J'ai essayé d'intégrer dans la fonction Demo.areaHandleClick le prompt. Il me le propose bien et j'ai essayé de définir le message affiché (sans utiliser le dialog pour l'instant) en fonction de la correspondance entre la réponse et le data-id
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    Demo.areaHandleClick = function (e) {
      const elClicked = e.target;
      const imgFond = document.getElementById("img-fond");
      if (imgFond.classList.contains("img-disabled")) {
        Demo.changeState(true);
      }
     
    // Intégration du code pour utiliser le prompt   
     
         const result = prompt("Entre le nom du jeu :" , "");
      // traitement cas où appui sur annuler
      if (null === result) return;
      // test réponse
      // si réponse OK, il faudrait faire peut-être plus de contrôle
      // comme minuscule/MAJUSCULE, enlever les espaces début et fin ...
      if (result === elClicked["data-id"]) {
     
     
     
        let win;
          win="Bravo, c'était bien "+elClicked["data-id"];
            // diffère l'affichage de la boîte alert
           Demo.showModal(msg);
        //setTimeout(() => alert(win), 100);  
        compt += 1;
        document.getElementById("champDuPrompt").innerHTML = compt;
        // (1) suppression de l'écouteur
        elClicked.removeEventListener("click", Demo.areaHandleClick);  // fonctionSurClic est le nom de la fonction appelée
     
      // ajout création d'un point sur l'image
          addPointOnImage(elClicked);
     
     
     
     
     
      }
      // réponse nOK
      else {
        let msg;
        vie -= 1;
        // mise à jour affichage nbr vies
        setNbrVies(vie);
        document.getElementById("nbdevies").innerHTML = vie;
        // traitement résultat
        if (vie == 0) {
          msg = "GAME OVER";
        }
        else {
            if (vie!=1){msg = "Il ne vous reste plus que " + vie + " vies";}
            else {msg = "Il ne vous reste plus que " + vie + " vie";}
        }
        // diffère l'affichage de la boîte alert
    // setTimeout(() => alert(msg), 100);
       Demo.showModal(msg);
      }
     
     
     
      /*const msg = elClicked.dataset.info || `le <b>${elClicked.getAttribute("shape")}<\/b> de couleur <b>${elClicked.dataset.id}<\/b>.`;
      Demo.showModal(msg);*/
    }
    Ben ça marche pas, je me dis que je dois mal définir la réponse.


    Le plus simple est de supprimer purement et simplement l'élément <area> sans rien faire d'autre. Tout ce qui le concerne disparaitra.
    Alors là aussi, j'ai essayé sans succès. Je me suis dit que je devais peut-être utilisé Element.remove()?

    Le cosmétique est à mettre en place en final mais là la gestion des alert, confirm et prompt est plus délicate et il est impossible de remplacer complètement les boîtes de dialogue JavaScript avec des fonctionnalités identiques.
    J'essaie déjà d'y penser car j'ai l'impression que pour transformer le prompt en dialog, je déconstruit tout à chaque fois.


    PS: Peut-être il ne faut pas que je commente dans ce sujet car cela ne correspond pas totalement à l'intitulé (même si c'est ce que je cherche à faire -> rendre le jeu responsive.

  7. #7
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    16 939
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 16 939
    Points : 44 112
    Points
    44 112
    Par défaut
    PS: Peut-être il ne faut pas que je commente dans ce sujet car cela ne correspond pas totalement à l'intitulé (même si c'est ce que je cherche à faire -> rendre le jeu responsive.
    Voilà une remarque qu'elle est pertinente et je me contenterais ici de répondre à celle-ci

    Pour rendre ta map resposive il te suffit de mettre en bas de ta page le code de la fonction, en supprimant l'appel à Demo.updateOverlay(area.dataset.id, shape, newCoords) et de rajouter l'appel à responsiveArea() juste après.

    Donc dans ton code :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    function responsiveArea(selector) {
      selector = selector || "[usemap]";
      // ... le corps de la fonction sans "Demo.blabla"
    }
    responsiveArea();

    Quelques remarques quand même, beaucoup d'erreurs dans ton code, aide toi de la console, F12, pour y voir plus clair.

    Par exemple :

    addPointOnImage(elClicked) fonction inexistante dans le lien fourni, donc ça plante !

    if (result === elClicked["data-id"]) "criture fantésiste, il faut mettre elClicked["dataset"]["id"]) !

    tu fais un let win mais tu passes msg : Demo.showModal(msg), il va pas aimer !

    ... et surement d'autres ...

    Il te faut donc plus de rigueur et avancer étape par étape en repartant de quelque chose qui fonctionne sans chercher à chasser plusieurs lièvres à la fois.

  8. #8
    Membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2018
    Messages
    166
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2018
    Messages : 166
    Points : 61
    Points
    61
    Par défaut
    Merci beaucoup, les infos m'ont permis de rendre mon jeu responsive.

  9. #9
    Membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2018
    Messages
    166
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2018
    Messages : 166
    Points : 61
    Points
    61
    Par défaut
    Bonjour, j'essaie de rendre cet affichage responsive en utilisant le code que tu as mis, mais je n'y arrive pas.

    Ai-je raté quelque chose?

    Ce post fait référence à ce sujet.

    Merci d'avance

  10. #10
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    16 939
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 16 939
    Points : 44 112
    Points
    44 112
    Par défaut
    j'ai un peu zappé !!!!

    Tu définies bien la fonction responsiveArea mais tu ne l'appelles pas dans ton code.

    De plus je vois que tu utilises le plugin maphilight by David Lynch, dans ce cas je te propose de regarder cette page : Plugin maphilight by David Lynch, elle pourrait t'aider.

Discussions similaires

  1. Rendre une pagination responsive
    Par flexi2202 dans le forum Mise en page CSS
    Réponses: 2
    Dernier message: 09/12/2021, 12h00
  2. Peut-on rendre une image parallax responsive ?
    Par dhillig dans le forum Mise en page CSS
    Réponses: 7
    Dernier message: 09/12/2021, 11h10
  3. Rendre une carte interactive et responsive
    Par Posoroko dans le forum Mise en page CSS
    Réponses: 2
    Dernier message: 04/12/2020, 09h29
  4. Rendre une div responsive en hauteur avec FlexBox
    Par wChris79 dans le forum Mise en page CSS
    Réponses: 5
    Dernier message: 20/05/2018, 14h50
  5. Réponses: 1
    Dernier message: 28/09/2010, 12h26

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo