it-swarm.dev

Como posso criar marcadores de mapa numerados no Google Maps V3?

Eu estou trabalhando em um mapa que tem vários marcadores nele.

Esses marcadores usam um ícone personalizado, mas eu também gostaria de adicionar números no topo. Eu vi como isso foi feito usando versões mais antigas da API. Como posso fazer isso na V3?

* Observação - o atributo "título" cria uma dica de ferramenta quando você passa o mouse sobre o marcador, mas eu quero algo que seja colocado sobre a imagem personalizada mesmo quando você não estiver pairando sobre ela.

Esta é a documentação da classe do marcador, e nenhum desses atributos parece ajudar: http://code.google.com/apis/maps/documentation/v3/reference.html#MarkerOptions

56
marclar

Infelizmente não é muito fácil. Você pode criar seu próprio marcador personalizado baseado na classe OverlayView ( um exemplo ) e colocar seu próprio HTML nele, incluindo um contador. Isso vai deixar você com um marcador muito básico, que você não pode arrastar ou adicionar sombras facilmente, mas é muito personalizável.

Alternativamente, você poderia adicionar um rótulo ao marcador padrão . Isso será menos personalizável, mas deve funcionar. Ele também mantém todas as coisas úteis que o marcador padrão faz.

Você pode ler mais sobre as sobreposições no artigo do Google Fun with MVC Objects .

Editar: se você não quiser criar uma classe JavaScript, poderá usar API de gráficos do Google . Por exemplo:

Marcador numerado: 

http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=7|FF0000|000000

Marcador de texto: 

http://chart.apis.google.com/chart?chst=d_map_spin&chld=1|0|FF0000|12|_|foo

Essa é a rota rápida e fácil, mas é menos personalizável e exige que uma nova imagem seja baixada pelo cliente para cada marcador.

62
dave1010

É assim que eu faço na V3:

Eu começo carregando a API do google maps e dentro do método de retorno de chamada initialize() eu carrego MarkerWithLabel.js que eu encontrei aqui :

function initialize() {

            $.getScript("/js/site/marker/MarkerWithLabel.js#{applicationBean.version}", function(){

            var mapOptions = {
                zoom: 8,
                center: new google.maps.LatLng(currentLat, currentLng),
                mapTypeId: google.maps.MapTypeId.ROADMAP,
                streetViewControl: false,
                mapTypeControl: false
            };

            var map = new google.maps.Map(document.getElementById('mapholder'),
                    mapOptions);

            var bounds = new google.maps.LatLngBounds();

            for (var i = 0; i < mapData.length; i++) {
                createMarker(i+1, map, mapData[i]); <!-- MARKERS! -->
                extendBounds(bounds, mapData[i]);
            }
            map.fitBounds(bounds);
            var maximumZoomLevel = 16;
            var minimumZoomLevel = 11;
            var ourZoom = defaultZoomLevel; // default zoom level

            var blistener = google.maps.event.addListener((map), 'bounds_changed', function(event) {
                if (this.getZoom(map.getBounds) &gt; 16) {
                    this.setZoom(maximumZoomLevel);
                }
                google.maps.event.removeListener(blistener);
            });
            });
        }

        function loadScript() {
            var script = document.createElement('script');
            script.type = 'text/javascript';
            script.src = "https://maps.googleapis.com/maps/api/js?v=3.exp&amp;libraries=places&amp;sensor=false&amp;callback=initialize";
            document.body.appendChild(script);
        }

        window.onload = loadScript;

    </script> 

Eu então crio os marcadores com createMarker():

function createMarker(number, currentMap, currentMapData) {

   var marker = new MarkerWithLabel({
       position: new google.maps.LatLng(currentMapData[0], currentMapData[1]),
                 map: currentMap,
                 icon: '/img/sticker/empty.png',
                 shadow: '/img/sticker/bubble_shadow.png',
                 transparent: '/img/sticker/bubble_transparent.png',
                 draggable: false,
                 raiseOnDrag: false,
                 labelContent: ""+number,
                 labelAnchor: new google.maps.Point(3, 30),
                 labelClass: "mapIconLabel", // the CSS class for the label
                 labelInBackground: false
                });
            }

Desde que eu adicionei mapIconLabel classe para o marcador eu posso adicionar algumas regras css no meu css:

.mapIconLabel {
    font-size: 15px;
    font-weight: bold;
    color: #FFFFFF;
    font-family: 'DINNextRoundedLTProMediumRegular';
}

E aqui está o resultado:

MarkerWithIconAndLabel

47
jakob

Não tenho reputação suficiente para comentar as respostas, mas queria observar que a API de gráficos do Google foi descontinuada.

Na página inicial da API :

A parte Infográficos do Google Chart Tools foi oficialmente Suspensa em 20 de abril de 2012.

27
Alex

Você pode querer baixar um conjunto de ícones numerados das fontes fornecidas neste site:

Então você deve ser capaz de fazer o seguinte:

<!DOCTYPE html>
<html> 
<head> 
    <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
    <title>Google Maps Demo</title> 
    <script type="text/javascript"
            src="http://maps.google.com/maps/api/js?sensor=false"></script> 

    <script type="text/javascript"> 
    function initialize() {

      var myOptions = {
        zoom: 11,
        center: new google.maps.LatLng(-33.9, 151.2),
        mapTypeId: google.maps.MapTypeId.ROADMAP
      }

      var map = new google.maps.Map(document.getElementById("map"), myOptions);

      var locations = [
        ['Bondi Beach', -33.890542, 151.274856, 4],
        ['Coogee Beach', -33.923036, 151.259052, 5],
        ['Cronulla Beach', -34.028249, 151.157507, 3],
        ['Manly Beach', -33.80010128657071, 151.28747820854187, 2],
        ['Maroubra Beach', -33.950198, 151.259302, 1]
      ];

      for (var i = 0; i < locations.length; i++) {
          var image = new google.maps.MarkerImage('marker' + i + '.png',
                      new google.maps.Size(20, 34),
                      new google.maps.Point(0, 0),
                      new google.maps.Point(10, 34));

          var location = locations[i];
          var myLatLng = new google.maps.LatLng(location[1], location[2]);
          var marker = new google.maps.Marker({
              position: myLatLng,
              map: map,
              icon: image,
              title: location[0],
              zIndex: location[3]
          });
      }
    }
    </script> 
</head> 
<body style="margin:0px; padding:0px;" onload="initialize();"> 
    <div id="map" style="width:400px; height:500px;"></div> 
</body> 
</html>

Captura de tela do exemplo acima:

Google Numbered Marker Icons

Note que você pode facilmente adicionar uma sombra atrás dos marcadores. Você pode verificar o exemplo na Referência da API do Google Maps: Marcadores complexos para mais informações sobre isso.

21
Daniel Vassallo

Isso agora foi adicionado à documentação de mapeamento e não requer nenhum código de terceiros. 

Você pode combinar essas duas amostras:

https://developers.google.com/maps/documentation/javascript/examples/marker-labels

https://developers.google.com/maps/documentation/javascript/examples/icon-simple

Para obter código como este:

var labelIndex = 0;
var labels = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789';

function initialize() {
  var bangalore = { lat: 12.97, lng: 77.59 };
  var map = new google.maps.Map(document.getElementById('map-canvas'), {
    zoom: 12,
    center: bangalore
  });

  // This event listener calls addMarker() when the map is clicked.
  google.maps.event.addListener(map, 'click', function(event) {
    addMarker(event.latLng, map);
  });

  // Add a marker at the center of the map.
  addMarker(bangalore, map);
}

// Adds a marker to the map.
function addMarker(location, map) {
  // Add the marker at the clicked location, and add the next-available label
  // from the array of alphabetical characters.
  var marker = new google.maps.Marker({
    position: location,
    label: labels[labelIndex],
    map: map,
    icon: 'image.png'
  });
}

google.maps.event.addDomListener(window, 'load', initialize);

Observe que, se você tiver mais de 35 marcadores, esse método não funcionará, pois o rótulo mostra apenas o primeiro caractere (usando A-Z e 0-9 faz 35). Vote por este Problema do Google Maps para solicitar que essa restrição seja suspensa.

14
John

Eu fiz isso usando uma solução semelhante à @ZuzEL.

Em vez de usar a solução padrão ( http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=7|FF0000|000000 ), você pode criar essas imagens como desejar, usando JavaScript, sem qualquer código do lado do servidor.

O google.maps.Marker aceita o Base64 por sua propriedade de ícone. Com isso, podemos criar uma Base64 válida a partir de um SVG.

enter image description here

Você pode ver o código para produzir o mesmo que esta imagem neste Plunker: http://plnkr.co/edit/jep5mVN3DsVRgtlz1GGQ?p=preview

var markers = [
  [1002, -14.2350040, -51.9252800],
  [2000, -34.028249, 151.157507],
  [123, 39.0119020, -98.4842460],
  [50, 48.8566140, 2.3522220],
  [22, 38.7755940, -9.1353670],
  [12, 12.0733335, 52.8234367],
];

function initializeMaps() {
  var myLatLng = {
    lat: -25.363,
    lng: 131.044
  };

  var map = new google.maps.Map(document.getElementById('map_canvas'), {
    zoom: 4,
    center: myLatLng
  });

  var bounds = new google.maps.LatLngBounds();

  markers.forEach(function(point) {
    generateIcon(point[0], function(src) {
      var pos = new google.maps.LatLng(point[1], point[2]);

      bounds.extend(pos);

      new google.maps.Marker({
        position: pos,
        map: map,
        icon: src
      });
    });
  });

  map.fitBounds(bounds);
}

var generateIconCache = {};

function generateIcon(number, callback) {
  if (generateIconCache[number] !== undefined) {
    callback(generateIconCache[number]);
  }

  var fontSize = 16,
    imageWidth = imageHeight = 35;

  if (number >= 1000) {
    fontSize = 10;
    imageWidth = imageHeight = 55;
  } else if (number < 1000 && number > 100) {
    fontSize = 14;
    imageWidth = imageHeight = 45;
  }

  var svg = d3.select(document.createElement('div')).append('svg')
    .attr('viewBox', '0 0 54.4 54.4')
    .append('g')

  var circles = svg.append('circle')
    .attr('cx', '27.2')
    .attr('cy', '27.2')
    .attr('r', '21.2')
    .style('fill', '#2063C6');

  var path = svg.append('path')
    .attr('d', 'M27.2,0C12.2,0,0,12.2,0,27.2s12.2,27.2,27.2,27.2s27.2-12.2,27.2-27.2S42.2,0,27.2,0z M6,27.2 C6,15.5,15.5,6,27.2,6s21.2,9.5,21.2,21.2c0,11.7-9.5,21.2-21.2,21.2S6,38.9,6,27.2z')
    .attr('fill', '#FFFFFF');

  var text = svg.append('text')
    .attr('dx', 27)
    .attr('dy', 32)
    .attr('text-anchor', 'middle')
    .attr('style', 'font-size:' + fontSize + 'px; fill: #FFFFFF; font-family: Arial, Verdana; font-weight: bold')
    .text(number);

  var svgNode = svg.node().parentNode.cloneNode(true),
    image = new Image();

  d3.select(svgNode).select('clippath').remove();

  var xmlSource = (new XMLSerializer()).serializeToString(svgNode);

  image.onload = (function(imageWidth, imageHeight) {
    var canvas = document.createElement('canvas'),
      context = canvas.getContext('2d'),
      dataURL;

    d3.select(canvas)
      .attr('width', imageWidth)
      .attr('height', imageHeight);

    context.drawImage(image, 0, 0, imageWidth, imageHeight);

    dataURL = canvas.toDataURL();
    generateIconCache[number] = dataURL;

    callback(dataURL);
  }).bind(this, imageWidth, imageHeight);

  image.src = 'data:image/svg+xml;base64,' + btoa(encodeURIComponent(xmlSource).replace(/%([0-9A-F]{2})/g, function(match, p1) {
    return String.fromCharCode('0x' + p1);
  }));
}

initializeMaps();
#map_canvas {
  width: 100%;
  height: 300px;
}
<!DOCTYPE html>
<html>

  <head>
    <link rel="stylesheet" href="style.css">
    
    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
    
  </head>

  <body>
    <div id="map_canvas"></div>
  </body>
  
  <script src="script.js"></script>

</html>

Nesta demo, eu crio o SVG usando D3.js e, em seguida, o SVG é transformado em Canvas, para que eu possa redimensionar a imagem como eu quero e depois eu recebo o Base64 do método canvas 'toDataURL.

Toda essa demonstração foi baseada no código do meu colega @ thiago-mata. Parabéns por ele.

10
Estevão Lucas

Que tal agora? (ano de 2015)

1) Obtenha uma imagem de marcador personalizada.

var imageObj = new Image();
    imageObj.src = "/markers/blank_pin.png"; 

2) Crie um canvas em RAM e desenhe esta imagem nele

imageObj.onload = function(){
    var canvas = document.createElement('canvas');
    var context = canvas.getContext("2d");
    context.drawImage(imageObj, 0, 0);
}

3) Escreva algo acima dele 

context.font = "40px Arial";
context.fillText("54", 17, 55);

4) Obtenha dados brutos da tela e forneça-os à API do Google em vez de ao URL

var image = {
    url: canvas.toDataURL(),
 };
 new google.maps.Marker({
    position: position,
    map: map,
    icon: image
 });

enter image description here

Código completo: 

function addComplexMarker(map, position, label, callback){
    var canvas = document.createElement('canvas');
    var context = canvas.getContext("2d");
    var imageObj = new Image();
    imageObj.src = "/markers/blank_pin.png";
    imageObj.onload = function(){
        context.drawImage(imageObj, 0, 0);

        //Adjustable parameters
        context.font = "40px Arial";
        context.fillText(label, 17, 55);
        //End

        var image = {
            url: canvas.toDataURL(),
            size: new google.maps.Size(80, 104),
            Origin: new google.maps.Point(0,0),
            anchor: new google.maps.Point(40, 104)
        };
        // the clickable region of the icon.
        var shape = {
            coords: [1, 1, 1, 104, 80, 104, 80 , 1],
            type: 'poly'
        };
        var marker = new google.maps.Marker({
            position: position,
            map: map,
            labelAnchor: new google.maps.Point(3, 30),
            icon: image,
            shape: shape,
            zIndex: 9999
        });
        callback && callback(marker)
    };
});
9
ZuzEL

A versão 3 do Google Maps tem suporte interno para marcadores de marcadores. Não é mais necessário gerar suas próprias imagens ou implementar classes de terceiros. Marcador de Etiquetas

5
ummdorian

É bastante viável gerar ícones rotulados do lado do servidor, se você tiver algumas habilidades de programação. Você precisará da biblioteca Gd no servidor, além do PHP. Está funcionando bem para mim há vários anos, mas é complicado fazer as imagens dos ícones em sincronia.

Eu faço isso via AJAX enviando os poucos parâmetros para definir o ícone em branco e o texto e cor, assim como bgcolor a ser aplicado. Aqui está meu PHP:

header("Content-type: image/png");
//$img_url = "./icons/gen_icon5.php?blank=7&text=BB";

function do_icon ($icon, $text, $color) {
$im = imagecreatefrompng($icon);
imageAlphaBlending($im, true);
imageSaveAlpha($im, true);

$len = strlen($text);
$p1 = ($len <= 2)? 1:2 ;
$p2 = ($len <= 2)? 3:2 ;
$px = (imagesx($im) - 7 * $len) / 2 + $p1;
$font = 'arial.ttf';
$contrast = ($color)? imagecolorallocate($im, 255, 255, 255): imagecolorallocate($im, 0, 0, 0); // white on dark?

imagestring($im, $p2, $px, 3, $text, $contrast);    // imagestring  ( $image, $font, $x, $y, $string, $color)

imagepng($im);
imagedestroy($im);
}
$icons =   array("black.png", "blue.png", "green.png", "red.png", "white.png", "yellow.png", "gray.png", "lt_blue.png", "orange.png");      // 1/9/09
$light =   array( TRUE,         TRUE,       FALSE,       FALSE,     FALSE,      FALSE,      FALSE,          FALSE,      FALSE);     // white text?

$the_icon = $icons[$_GET['blank']];             // 0 thru 8 (note: total 9)
$the_text = substr($_GET['text'], 0, 3);        // enforce 2-char limit
do_icon ($the_icon, $the_text,$light[$_GET['blank']] ); 

É invocado pelo lado do cliente através de algo como o seguinte: Var image_file = "./our_icons/gen_icon.php?blank=" + escape (ícones [cor]) + "& text =" + iconStr;

3
user1032402

Meus dois centavos mostrando como usar a Google Charts API para resolver esse problema.

2
sebastian serrano

Você pode usar a opção Marker With Label no google-maps-utility-library-v3. enter image description here

Basta indicar https://code.google.com/p/google-maps-utility-library-v3/wiki/Libraries

0
bCliks

Talvez existam aqueles que ainda procuram por isso, mas considerem os ícones do Google Dynamic obsoletos e outras bibliotecas de ícones de mapas um pouco feios demais.

Para adicionar um marcador simples com qualquer número dentro de um URL. No Google Drive que usa o Google My Maps, ele cria ícones numerados ao usar uma camada de mapa definida como "Sequência de números" e, em seguida, adicionar marcadores/pontos no mapa.

Olhando para o código-fonte, o Google tem seu próprio jeito de fazer isso por meio de um URL:

https://mt.google.com/vt/icon/name=icons/onion/SHARED-mymaps-container-bg_4x.png,icons/onion/SHARED-mymaps-container_4x.png,icons/onion/1738-blank-sequence_4x.png&highlight=ff000000,0288D1,ff000000&scale=2.0&color=ffffffff&psize=15&text=56&font=fonts/Roboto-Medium.ttf

Acima do URL

enter image description here

Eu não tenho tocado muito com isso, mas mudando os códigos de cores hexadecimais no parâmetro 'highlight' (o parâmetro color não muda a cor como você pode pensar), o valor 'text' pode ser ajustado para qualquer string e você pode fazer Um belo ícone redondo com qualquer número/valor dentro. Tenho certeza de que os outros parâmetros também podem ser úteis.

Uma ressalva com essa abordagem, quem sabe quando o Google removerá esse URL do mundo!

0
Nado11

Baseado em @ dave1010 answer mas com links https atualizados.

Marcador numerado:

https://chart.googleapis.com/chart?chst=d_map_pin_letter&chld=7|FF0000|000000

Marcador de texto:

https://chart.googleapis.com/chart?chst=d_map_spin&chld=1|0|FF0000|12|_|Marker
0
Pedro Lobito

Eu descobri a melhor maneira de fazer isso. Use Snap.svg para criar o svg e, em seguida, use a função toDataURL () que cria os dados gráficos para incluir como ícone. Nota que eu uso a classe SlidingMarker para o marcador que me dá um bom movimento do marcador. Com o Snap.svg você pode criar qualquer tipo de gráfico e seu mapa ficará fantástico.

var s = Snap(100, 100);
s.text(50, 50, store.name);
// Use more graphics here.
var marker = new SlidingMarker({
  position: {lat: store.lat, lng: store.lng},
  map: $scope.map,
  label: store.name, // you do not need this
  title: store.name, // nor this
  duration: 2000,
  icon: s.toDataURL()
});
0
Αλέκος

SOLUÇÃO MAIS FÁCIL - USE SVG

Funciona em: in IE9, IE10, FF, Chrome, Safari

(se você estiver usando outros navegadores, por favor "Run code snippet" e coloque um comentário)

Nenhuma dependência externa além da API do Google Maps!

enter image description here

Isso é bastante fácil desde que você tenha seu ícone no formato .svg. Se esse for o caso, apenas add elemento de texto apropriado e altere seu conteúdo para atender às suas necessidades com JS.

Adicione algo assim ao seu código .svg (este é o texto "section" que será alterado mais tarde com JS):

<text id="1" fill="#20539F" font-family="NunitoSans-ExtraBold, Nunito Sans" font-size="18" font-weight="600" letter-spacing=".104" text-anchor="middle" x="50%" y="28">1</text>

Exemplo: (parcialmente copiado de @ EstevãoLucas)

Importante: Use as propriedades corretas da tag <text>. Observe text-anchor="middle" x="50%" y="28" que centraliza números maiores (mais informações: Como colocar e centralizar o texto em um retângulo SVG )

Use encodeURIComponent() (isso provavelmente garante a compatibilidade com o IE9 e 10)

// Most important part (use output as Google Maps icon)
function getMarkerIcon(number) {
  // inline your SVG image with number variable
  var svg = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="40" height="40" viewBox="0 0 40 40"> <defs> <rect id="path-1" width="40" height="40"/> <mask id="mask-2" width="40" height="40" x="0" y="0" fill="white"> <use xlink:href="#path-1"/> </mask> </defs> <g id="Page-1" fill="none" fill-rule="evenodd"> <g id="Phone-Portrait---320" transform="translate(-209 -51)"> <g id="Group" transform="translate(209 51)"> <use id="Rectangle" fill="#FFEB3B" stroke="#F44336" stroke-width="4" mask="url(#mask-2)" xlink:href="#path-1"/> <text id="1" fill="#20539F" font-family="NunitoSans-ExtraBold, Nunito Sans" font-size="18" font-weight="600" letter-spacing=".104" text-anchor="middle" x="50%" y="28">' + number + '</text> </g> </g> </g> </svg>';
  // use SVG without base64 see: https://css-tricks.com/probably-dont-base64-svg/
  return 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svg);
}

// Standard Maps API code
var markers = [
  [1, -14.2350040, -51.9252800],
  [2, -34.028249, 151.157507],
  [3, 39.0119020, -98.4842460],
  [5, 48.8566140, 2.3522220],
  [9, 38.7755940, -9.1353670],
  [12, 12.0733335, 52.8234367],
];

function initializeMaps() {
  var myLatLng = {
    lat: -25.363,
    lng: 131.044
  };

  var map = new google.maps.Map(document.getElementById('map_canvas'), {
    zoom: 4,
    center: myLatLng
  });

  var bounds = new google.maps.LatLngBounds();

  markers.forEach(function(point) {
      var pos = new google.maps.LatLng(point[1], point[2]);

      new google.maps.Marker({
        position: pos,
        map: map,
        icon: getMarkerIcon(point[0]),         
      });

      bounds.extend(pos);
  });

  map.fitBounds(bounds);
}

initializeMaps();
#map_canvas {
  width: 100%;
  height: 300px;
}
<!DOCTYPE html>
<html>

  <head>
    <link rel="stylesheet" href="style.css">
    
    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>        
  </head>

  <body>
    <div id="map_canvas"></div>
  </body>
  
  <script src="script.js"></script>

</html>

Mais informações sobre o inline SVG no Google Maps: https://robert.katzki.de/posts/inline-svg-as-google-maps-marker

0
jmarceli