web-dev-qa-db-fra.com

Carte d'image réactive

J'ai une carte-image existante dans une mise en page HTML réactive. Les images sont redimensionnées en fonction de la taille du navigateur, mais les coordonnées de l’image sont évidemment des tailles de pixels fixes. Quelles sont les options disponibles pour redimensionner les coordonnées de la carte?

117
jdog

Pour les cartes réactives, vous devrez utiliser un plugin:

https://github.com/stowball/jQuery-rwdImageMaps (n'est plus maintenu)

Ou

https://github.com/davidjbradshaw/imagemap-resizer


Aucun des principaux navigateurs ne comprend correctement les coordonnées en pourcentage, et tous interpréter les coordonnées en pourcentage sous forme de coordonnées en pixels.

http://www.howtocreate.co.uk/tutorials/html/imagemaps

Et aussi cette page pour tester si les navigateurs implémentent

http://home.comcast.net/~urbanjost/IMG/resizeimg3.html

81
Tom
39
Joshua Stewardson

Vous pouvez également utiliser svg au lieu d'une carte-image. ;)

Il y a un tutoriel sur comment faire cela.

.hover_group:hover {
  opacity: 1;
}
#projectsvg {
  position: relative;
  width: 100%;
  padding-bottom: 77%;
  vertical-align: middle;
  margin: 0;
  overflow: hidden;
}
#projectsvg svg {
  display: inline-block;
  position: absolute;
  top: 0;
  left: 0;
}
<figure id="projectsvg">
  <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1920 1080" preserveAspectRatio="xMinYMin meet" >
<!-- set your background image -->
<image width="1920" height="1080" xlink:href="http://placehold.it/1920x1080" />
<g class="hover_group" opacity="0">
  <a xlink:href="https://example.com/link1.html">
    <text x="652" y="706.9" font-size="20">First zone</text>
    <rect x="572" y="324.1" opacity="0.2" fill="#FFFFFF" width="264.6" height="387.8"></rect>
  </a>
</g>
<g class="hover_group" opacity="0">
  <a xlink:href="https://example.com/link2.html">
    <text x="1230.7" y="952" font-size="20">Second zone</text>
    <rect x="1081.7" y="507" opacity="0.2" fill="#FFFFFF" width="390.2" height="450"></rect>
  </a>
</g>
  </svg>
</figure>

30
belgac

Je suis tombé sur une solution qui n'utilise pas du tout de carte-image, mais plutôt des balises d'ancrage qui sont absolument positionnées sur l'image. Le seul inconvénient serait que le hotspot devrait être rectangulaire, mais le plus est que cette solution ne repose pas sur Javascript, mais sur CSS. Il existe un site Web que vous pouvez utiliser pour générer le code HTML pour les ancres: http://www.zaneray.com/responsive-image-map/

J'ai mis l'image et les balises d'ancrage générées dans une balise div relativement positionnée et tout fonctionnait parfaitement pour le redimensionnement de la fenêtre et sur mon téléphone portable.

14
Jeffrey Langham

David Bradshaw a écrit une jolie petite bibliothèque qui résout ce problème. Il peut être utilisé avec ou sans jQuery.

Disponible ici: https://github.com/davidjbradshaw/imagemap-resizer

11
Grodriguez

La méthode suivante fonctionne parfaitement pour moi, alors voici ma mise en œuvre complète:

<img id="my_image" style="display: none;" src="my.png" width="924" height="330" border="0" usemap="#map" />

<map name="map" id="map">
    <area shape="poly" coords="774,49,810,21,922,130,920,222,894,212,885,156,874,146" href="#mylink" />
    <area shape="poly" coords="649,20,791,157,805,160,809,217,851,214,847,135,709,1,666,3" href="#myotherlink" />
</map>

<script>
$(function(){
    var image_is_loaded = false;
    $("#my_image").on('load',function() {
        $(this).data('width', $(this).attr('width')).data('height', $(this).attr('height'));
        $($(this).attr('usemap')+" area").each(function(){
            $(this).data('coords', $(this).attr('coords'));
        });

        $(this).css('width', '100%').css('height','auto').show();

        image_is_loaded = true;
        $(window).trigger('resize');
    });


    function ratioCoords (coords, ratio) {
        coord_arr = coords.split(",");

        for(i=0; i < coord_arr.length; i++) {
            coord_arr[i] = Math.round(ratio * coord_arr[i]);
        }

        return coord_arr.join(',');
    }
    $(window).on('resize', function(){
        if (image_is_loaded) {
            var img = $("#my_image");
            var ratio = img.width()/img.data('width');

            $(img.attr('usemap')+" area").each(function(){
                console.log('1: '+$(this).attr('coords'));
                $(this).attr('coords', ratioCoords($(this).data('coords'), ratio));
            });
        }
    });
});
</script>
6
chimeraha

Vous pouvez obtenir une image de carte sensible en utilisant le lien ci-dessous

window.onload = function () {
    var ImageMap = function (map, img) {
            var n,
                areas = map.getElementsByTagName('area'),
                len = areas.length,
                coords = [],
                previousWidth = 128;
            for (n = 0; n < len; n++) {
                coords[n] = areas[n].coords.split(',');
            }
            this.resize = function () {
                var n, m, clen,
                    x = img.offsetWidth / previousWidth;
                for (n = 0; n < len; n++) {
                    clen = coords[n].length;
                    for (m = 0; m < clen; m++) {
                        coords[n][m] *= x;
                    }
                    areas[n].coords = coords[n].join(',');
                }
                previousWidth = document.body.clientWidth;
                return true;
            };
            window.onresize = this.resize;
        },
        imageMap = new ImageMap(document.getElementById('map_ID'), document.getElementById('img_ID'));
    imageMap.resize();
    return;
}
<div style="width:100%;">
    <img id="img_ID" src="http://www.gravatar.com/avatar/0865e7bad648eab23c7d4a843144de48?s=128&d=identicon&r=PG" usemap="#map" border="0" width="100%" alt="" />
</div>
<map id="map_ID" name="map">
<area shape="poly" coords="48,10,80,10,65,42" href="javascript:;" alt="Bandcamp" title="Bandcamp" />
<area shape="poly" coords="30,50,62,50,46,82" href="javascript:;" alt="Facebook" title="Facebook" />
<area shape="poly" coords="66,50,98,50,82,82" href="javascript:;" alt="Soundcloud" title="Soundcloud" />
</map>

Travailler pour moi (n'oubliez pas de changer 3 choses dans le code):

  • previousWidth (taille originale de l'image)

  • map_ID (id de votre carte d'image)

  • img_ID (id de votre image)

HTML:

<div style="width:100%;">
    <img id="img_ID" src="http://www.gravatar.com/avatar/0865e7bad648eab23c7d4a843144de48?s=128&d=identicon&r=PG" usemap="#map" border="0" width="100%" alt="" />
</div>
<map id="map_ID" name="map">
<area shape="poly" coords="48,10,80,10,65,42" href="javascript:;" alt="Bandcamp" title="Bandcamp" />
<area shape="poly" coords="30,50,62,50,46,82" href="javascript:;" alt="Facebook" title="Facebook" />
<area shape="poly" coords="66,50,98,50,82,82" href="javascript:;" alt="Soundcloud" title="Soundcloud" />
</map>

Javascript:

window.onload = function () {
    var ImageMap = function (map, img) {
            var n,
                areas = map.getElementsByTagName('area'),
                len = areas.length,
                coords = [],
                previousWidth = 128;
            for (n = 0; n < len; n++) {
                coords[n] = areas[n].coords.split(',');
            }
            this.resize = function () {
                var n, m, clen,
                    x = img.offsetWidth / previousWidth;
                for (n = 0; n < len; n++) {
                    clen = coords[n].length;
                    for (m = 0; m < clen; m++) {
                        coords[n][m] *= x;
                    }
                    areas[n].coords = coords[n].join(',');
                }
                previousWidth = img.offsetWidth;
                return true;
            };
            window.onresize = this.resize;
        },
        imageMap = new ImageMap(document.getElementById('map_ID'), document.getElementById('img_ID'));
    imageMap.resize();
    return;
}

JSFiddle: http://jsfiddle.net/p7EyT/154/

3
Niente0

Je viens avec la même exigence où, je veux montrer la carte-image sensible qui peut redimensionner avec n'importe quelle taille d'écran et la chose importante est, je veux mettre en surbrillance les coordonnées.

J'ai donc essayé de nombreuses bibliothèques qui peuvent redimensionner les coordonnées en fonction de la taille de l'écran et de l'événement. Et j’ai eu la meilleure solution (jquery.imagemapster.min.js) qui fonctionne très bien avec presque tous les navigateurs. Aussi, je l'ai intégré avec Summer Plgin qui crée une carte graphique.

 var resizeTime = 100;
 var resizeDelay = 100;    

$('img').mapster({
        areas: [
            {
                key: 'tbl',
                fillColor: 'ff0000',
                staticState: true,
                stroke: true
            }
        ],
        mapKey: 'state'
    });

    // Resize the map to fit within the boundaries provided

    function resize(maxWidth, maxHeight) {
        var image = $('img'),
            imgWidth = image.width(),
            imgHeight = image.height(),
            newWidth = 0,
            newHeight = 0;

        if (imgWidth / maxWidth > imgHeight / maxHeight) {
            newWidth = maxWidth;
        } else {
            newHeight = maxHeight;
        }
        image.mapster('resize', newWidth, newHeight, resizeTime);
    }

    function onWindowResize() {

        var curWidth = $(window).width(),
            curHeight = $(window).height(),
            checking = false;
        if (checking) {
            return;
        }
        checking = true;
        window.setTimeout(function () {
            var newWidth = $(window).width(),
                newHeight = $(window).height();
            if (newWidth === curWidth &&
                newHeight === curHeight) {
                resize(newWidth, newHeight);
            }
            checking = false;
        }, resizeDelay);
    }

    $(window).bind('resize', onWindowResize);
img[usemap] {
        border: none;
        height: auto;
        max-width: 100%;
        width: auto;
    }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.imagemapster.min.js"></script>

<img src="https://discover.luxury/wp-content/uploads/2016/11/Cities-With-the-Most-Michelin-Star-Restaurants-1024x581.jpg" alt="" usemap="#map" />
<map name="map">
    <area shape="poly" coords="777, 219, 707, 309, 750, 395, 847, 431, 916, 378, 923, 295, 870, 220" href="#" alt="poly" title="Polygon" data-maphilight='' state="tbl"/>
    <area shape="circle" coords="548, 317, 72" href="#" alt="circle" title="Circle" data-maphilight='' state="tbl"/>
    <area shape="rect" coords="182, 283, 398, 385" href="#" alt="rect" title="Rectangle" data-maphilight='' state="tbl"/>
</map>

J'espère l'aider à quelqu'un.

2
Rahul Mahadik

http://home.comcast.net/~urbanjost/semaphore.html est la page d'accueil de la discussion et contient en fait des liens vers une solution JavaScript du problème. J'ai reçu un avis Indiquant que HTML prendrait en charge le pourcentage d'unités dans le futur, mais je n'ai constaté aucun progrès à cet égard. par conséquent, la solution de rechange mérite probablement d'être examinée si vous êtes à l'aise avec JavaScript/ECMAScript.

2
John Urban

Cela dépend, vous pouvez utiliser jQuery pour ajuster les plages proportionnellement, je pense ... Pourquoi utilisez-vous une carte graphique au fait? Ne pouvez-vous pas utiliser des divs de redimensionnement ou d'autres éléments pour cela?

1
Reinier Kaper

Découvrez le image-map plugin sur Github. Cela fonctionne à la fois avec JavaScript JavaScript et en tant que plugin jQuery.

$('img[usemap]').imageMap();     // jQuery

ImageMap('img[usemap]')          // JavaScript

Découvrez la démo .

1
Travis Clarke

Pour ceux qui ne veulent pas recourir à JavaScript, voici un exemple de découpage d'image:

http://codepen.io/anon/pen/cbzrK

Lorsque vous redimensionnez la fenêtre, l'image du clown sera redimensionnée en conséquence et, le cas échéant, le nez du clown reste lié à un lien.

1
Johnny Oshika

Pour une raison quelconque, aucune de ces solutions ne fonctionnait pour moi. J'ai eu le meilleur succès en utilisant des transformations.

transform: translateX(-5.8%) translateY(-5%) scale(0.884);
0
Mike Furlender

J'ai trouvé un moyen non-JS de résoudre ce problème si vous êtes d'accord avec les zones d'impact rectangulaires.

Tout d’abord, assurez-vous que votre image se trouve dans une division relativement positionnée. Ensuite, placez l’image dans cette div, ce qui signifie qu’elle occupera tout l’espace de la div. Enfin, ajoutez des divisions absolues sous l'image, dans la division principale, et utilisez des pourcentages pour haut, gauche, largeur et hauteur afin que le lien atteigne la taille et la position souhaitées.

Je trouve qu'il est plus facile de donner à la div une couleur de fond noire (idéalement avec un fondu alpha afin de voir le contenu lié en dessous) lorsque vous travaillez pour la première fois, et d'utiliser un inspecteur de code dans votre navigateur pour ajuster les pourcentages en temps réel , afin que vous puissiez l'obtenir juste.

Voici le schéma de base avec lequel vous pouvez travailler. En faisant tout avec des pourcentages, vous vous assurez que les éléments conservent tous la même taille et la même position relatives à l’échelle de l’image.

<div style="position: relative;">
  <img src="background-image.png" style="width: 100%; height: auto;">
  <a href="/link1"><div style="position: absolute; left: 15%; top: 20%; width: 12%; height: 8%; background-color: rgba(0, 0, 0, .25);"></div></a>
  <a href="/link2"><div style="position: absolute; left: 52%; top: 38%; width: 14%; height: 20%; background-color: rgba(0, 0, 0, .25);"></div></a>
</div>

Utilisez ce code avec votre inspecteur de code dans Chrome ou le navigateur de votre choix et ajustez les pourcentages (vous pouvez utiliser des pourcentages décimaux plus exacts) jusqu'à ce que les zones soient parfaitement correctes. Choisissez également un background-color de transparent lorsque vous êtes prêt à l'utiliser, car vous souhaitez que vos zones actives soient invisibles.

0
Tom Bisciglia

largeur de réponse && hauteur

window.onload = function () {
        var ImageMap = function (map, img) {
                var n,
                    areas = map.getElementsByTagName('area'),
                    len = areas.length,
                    coords = [],
                    imgWidth = img.naturalWidth,
                    imgHeight = img.naturalHeight;
                for (n = 0; n < len; n++) {
                    coords[n] = areas[n].coords.split(',');
                }
            this.resize = function () {
                var n, m, clen,
                    x = img.offsetWidth / imgWidth,
                    y = img.offsetHeight / imgHeight;
                    imgWidth = img.offsetWidth;
                    imgHeight = img.offsetHeight;
                for (n = 0; n < len; n++) {
                    clen = coords[n].length;
                    for (m = 0; m < clen; m +=2) {
                        coords[n][m] *= x;
                        coords[n][m+1] *= y;
                    }
                    areas[n].coords = coords[n].join(',');
                }
                    return true;
                };
                window.onresize = this.resize;
            },
        imageMap = new ImageMap(document.getElementById('map_region'), document.getElementById('prepay_region'));
        imageMap.resize();
        return;
    }

Semblable à la réponse d'Orland ici: https://stackoverflow.com/a/32870380/462781

Combiné avec le code de Chris ici: https://stackoverflow.com/a/12121309/462781

Si les zones s’intègrent dans une grille, vous pouvez les superposer avec des images transparentes en utilisant une largeur en% qui conserve leur rapport de format.

    .wrapperspace {
      width: 100%;
      display: inline-block;
      position: relative;
    }
    .mainspace {
      position: absolute;
      top: 0;
      bottom: 0;
      right: 0;
      left: 0;
    }
<div class="wrapperspace">
 <img style="float: left;" title="" src="background-image.png" width="100%" />
 <div class="mainspace">
     <div>
         <img src="space-top.png" style="margin-left:6%;width:15%;"/>
     </div>
     <div>
       <a href="http://www.example.com"><img src="space-company.png" style="margin-left:6%;width:15%;"></a>
     </div>
  <div>
   <a href="http://www.example.com"><img src="space-company.png" style="margin-left:6%;width:10%;"></a>
   <a href="http://www.example.com"><img src="space-company.png" style="width:20%;"></a>
  </div>
 </div>
</div>

Vous pouvez utiliser une marge en%. De plus, des images "d'espace" peuvent être placées l'une à côté de l'autre dans une div de troisième niveau.

0
Pete