Mapa de imagem responsivo


145

Eu tenho um mapa de imagem existente em um layout html responsivo. As imagens são dimensionadas de acordo com o tamanho do navegador, mas as coordenadas da imagem são obviamente tamanhos de pixels fixos. Quais são as opções que tenho para redimensionar as coordenadas do mapa de imagens?


6
Esta questão não é sobre um mapa geográfico, mas o <map> tag html
jdog

4
Confira o plugin de imagem-mapa . Ele funciona com Javascript, Nó, e jQuery
Travis Clarke

2
Como alternativa, você pode usar uma imagem SVG. Eu recomendo a leitura Usando SVG como An para mapas de imagem alternativos
MAWG diz restabelecer Monica

1
Parece que o que queremos é a capacidade de fazer upload de um JPEG ou semelhante a um aplicativo que permite especificar locais de mapas na imagem (como na rede de pontos de mapas de imagens) - em segundo plano, isso produz um arquivo SVG essencialmente transparente . Em seguida, queremos que o mapa seja aplicado ao SVG e renderize o SVG sobre o JPG no navegador da web. Como o navegador redimensiona o JPG, o SVG também é redimensionado e o SVG é sempre o invocado ao clicar no mapa da imagem. Alguma sugestão em alguma das partes disso?
Youcantryreachingme

2
Sim, isso é o que eu queria em 2011
jdog

Respostas:


89

Para mapas de imagem responsivos, você precisará usar um plugin:

https://github.com/stowball/jQuery-rwdImageMaps (não é mais mantido)

Ou

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


Nenhum navegador principal entende corretamente as coordenadas percentuais e todos interpretam as coordenadas percentuais como coordenadas de pixel.

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

E também esta página para testar se os navegadores implementam

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


5
isso ainda é relevante? você poderia fornecer uma atualização, por favor?
Malachi

1
@Malachi Sim, este ainda é relevante
Tom

obrigado Tom, nós estávamos tendo uma discussão sobre uma questão em codereview, agora eu gostaria de lembrar a pergunta ....
Malaquias

@ Tom isso funciona somente para uma image..if colocamos outra imagem, então não o seu trabalho para a segunda e terceira imagem etc ... apenas verificá-lo ..
User2413

1
Eu encontrei uma ferramenta de gerador on-line que usa SVGs que todos os principais navegadores entendem imagemapper.noc.io
frthjf

43

Você também pode usar svg em vez de um mapa de imagem. ;)

Há um tutorial sobre como fazer isso.

.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>


1
O link do tutorial está quebrado. A imagem do jsfiddle também.
Cristiano Maia

Eu sinalizei que o link do tutorial estava quebrado e atualizei o jsfiddle e os trechos de código. Obrigado a cabeça para cima
belgac

Esta é uma solução incrível. Eu o uso com sucesso e funciona como um encanto. Obrigado!
Jaume Mussons Abad

3
De longe a melhor solução em 2020. Experimente este gerador de código para torná-lo super simples. imagemapper.noc.io/#
Brett Donald

1
Essa deve ser a melhor solução responsiva em 2020.
mythicalcoder

39

1
Just e FYI para eveyrone ... Descobri que isso funciona bem, mas não dentro de um acordeão. Estou usando o Bootstrap 3 e se você não carregar a página com o acordeão aberto na imagem, quando você abrir o acordeão, o mapa da imagem não estará lá, a menos que a janela do navegador seja redimensionada.
Jasonflaherty

1
@jasonflaherty você poderia disparar um evento de redimensionamento para forçar a exibição do mapa? $(window).trigger('resize');
Steve Meisner

@SteveMeisner Eu não tentei isso ... mas isso não forçaria uma atualização?
Jasonflaherty 19/05

@jasonflaherty nope! Apenas "aciona" o evento de redimensionamento no elemento que você vincula ( windowneste caso). Boa sorte.
Steve Meisner

Acabou de criar o módulo de super básico, mas útil Drupal usando este plugin: drupal.org/project/responsive_imagemaps
Joshua Stewardson

19

Encontrei uma solução que não usa mapas de imagem, mas tags de âncora que estão absolutamente posicionadas sobre a imagem. A única desvantagem seria que o ponto de acesso teria que ser retangular, mas a vantagem é que essa solução não depende de Javascript, apenas de CSS. Existe um site que você pode usar para gerar o código HTML para as âncoras: http://www.zaneray.com/responsive-image-map/

Coloquei a imagem e as tags âncora geradas em uma tag div relativamente posicionada e tudo funcionou perfeitamente no redimensionamento da janela e no meu celular.


2
Bom achado! Obrigado por contribuir para esta lista
Jdog 29/03

1
Eu não posso aprovar este naswer o suficiente !! Um excelente tutorial; abrangente e fácil de entender. Deve-se ler tudo, mas de particular interesse é tutorials.jenkov.com/svg/scripting.html
Mawg diz que restabelece Monica em

Esta é uma solução realmente simples, mas agradável, se a área a ser clicada for um retângulo.
user2875289

Isso é tão incrível. Trabalhou para mim também com um site DNN. Como Jeffrey afirmou, acabei de soltar o <img> e o html gerado dentro de uma div relativa posicionada. Obrigado!
Ted Krapf

18

Eu encontrei uma maneira no-JS de resolver isso, se você estiver bem com áreas de acerto retangulares.

Antes de tudo, verifique se sua imagem está em uma div que está relativamente posicionada. Em seguida, coloque a imagem dentro desta div, o que significa que ela ocupará todo o espaço na div. Por fim, adicione divs absolutamente posicionadas sob a imagem, dentro da div principal, e use porcentagens para cima, esquerda, largura e altura para obter as áreas atingidas pelo link com o tamanho e a posição desejados.

Acho que é mais fácil dar à div uma cor de fundo preto (de preferência com algum desbotamento alfa para que você possa ver o conteúdo vinculado abaixo) quando estiver trabalhando pela primeira vez e usar um inspetor de código no navegador para ajustar as porcentagens em tempo real , para que você possa acertar.

Aqui está o esboço básico com o qual você pode trabalhar. Ao fazer tudo com porcentagens, você garante que todos os elementos permaneçam com o mesmo tamanho e posição relativos que a imagem é dimensionada.

<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>

Use esse código com seu inspetor de código no Chrome ou no navegador de sua escolha e ajuste as porcentagens (você pode usar porcentagens decimais para ser mais exato) até que as caixas estejam perfeitas. Também escolher um background-colorde transparentquando você estiver pronto para usá-lo desde que você quer suas áreas de vida para ser invisível.


Esta é uma otima soluçao! Obrigado
xims 14/03/19

Ótima solução! UIKit usa a mesma técnica para os seus marcadores: getuikit.com/docs/marker
xela84

Solução brilhante, obrigado por compartilhar! Estou usando isso em um aplicativo móvel e resolve o problema de diferentes telas.
JohnGIS 5/09/19


7

O método a seguir funciona perfeitamente para mim, então aqui está minha implementação completa:

<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>

4

Trabalhando para mim (lembre-se de alterar três coisas no código):

  • previousWidth (tamanho original da imagem)

  • map_ID (ID do seu mapa de imagens)

  • img_ID (ID da sua imagem)

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

Me deparei com o mesmo requisito, onde, eu quero mostrar um mapa de imagem responsivo que pode ser redimensionado com qualquer tamanho de tela e o importante é que eu quero destacar as coordenadas .

Então, eu tentei muitas bibliotecas que podem redimensionar coordenadas de acordo com o tamanho da tela e evento. E eu tenho a melhor solução (jquery.imagemapster.min.js), que funciona bem com quase todos os navegadores. Também o integrei com o Summer Plgin, que cria um mapa de imagens.

 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/jquery-imagemapster@1.2.10/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>

Espero ajudar com alguém.


2

http://home.comcast.net/~urbanjost/semaphore.html é a página inicial da discussão e, na verdade, possui links para uma solução baseada em JavaScript para o problema. Recebi um aviso de que o HTML oferecerá suporte a unidades percentuais no futuro, mas não vejo nenhum progresso nisso há algum tempo (provavelmente já faz mais de um ano desde que eu ouvi o suporte), portanto, a solução alternativa é provavelmente vale a pena examinar se você se sente confortável com JavaScript / ECMAScript.



1

Depende, você pode usar o jQuery para ajustar os intervalos proporcionalmente, eu acho. Por que você usa um mapa de imagem a propósito? Você não pode usar divs de escala ou outros elementos para isso?


embora a solução exata funcione com divs em escala, o mapa da imagem é "gerenciado por conteúdo" e permite qualquer tipo de região. Obrigado, vou verificar jquery para isso.
jdog


0

Semelhante à resposta de Orland aqui: https://stackoverflow.com/a/32870380/462781

Combinado com o código de Chris aqui: https://stackoverflow.com/a/12121309/462781

Se as áreas couberem em uma grade, você pode sobrepor as áreas por figuras transparentes, usando uma largura em% que mantém sua proporção.

    .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>

Você pode usar uma margem em%. Além disso, imagens de "espaço" podem ser colocadas próximas umas das outras dentro de uma div de terceiro nível.


0

Por alguma razão, nenhuma dessas soluções funcionou para mim. Eu tive o melhor sucesso usando transformações.

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

0

largura responsiva e altura

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;
    }

Você pode adicionar mais conteúdo mostrando as diferenças entre o seu código e a resposta da Niente0 a partir de 2015?
Michael - Onde está Clay Shirky,
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.