Come utilizzare i marcatori SVG nell'API di Google Maps v3


91

Posso usare il mio file image.svg convertito come icona della mappa di Google. Stavo convertendo la mia immagine png in svg e voglio usare questo come il simbolo della mappa di Google che può essere ruotato. Ho già provato a utilizzare il simbolo di google map ma voglio avere un'icona come auto, uomo, ecc ... Ecco perché ho convertito i miei alcuni file png in svg, proprio come questo sito di esempio cosa usa per questi http: / /www.goprotravelling.com/


1
Per coloro che cercano questa domanda simile: una soluzione parziale compatibile con IE 9+ qui: stackoverflow.com/a/30890373/634386 posizionerà un SVG nel DOM anziché sulla tela in modo da poter manipolare con CSS3 dopo (se tu ' stai cercando di ruotare quell'elemento in modo specifico al volo).
Mike Kormendy,

Risposte:


144

Puoi rendere la tua icona usando la notazione SVG Path .

Consulta la documentazione di Google per ulteriori informazioni.

Ecco un esempio di base:

var icon = {

    path: "M-20,0a20,20 0 1,0 40,0a20,20 0 1,0 -40,0",
    fillColor: '#FF0000',
    fillOpacity: .6,
    anchor: new google.maps.Point(0,0),
    strokeWeight: 0,
    scale: 1
}

var marker = new google.maps.Marker({
    position: event.latLng,
    map: map,
    draggable: false,
    icon: icon
});

Ecco un esempio funzionante su come visualizzare e ridimensionare un'icona SVG marker:

Demo di JSFiddle

Modificare:

Un altro esempio qui con un'icona complessa:

Demo di JSFiddle

Modifica 2:

Ed ecco come puoi avere un file SVG come icona:

Demo di JSFiddle


, è molto difficile creare svg per auto.
jemz

Hai un'immagine SVG dell'auto che desideri? Quindi aprilo con un editor di testo e trova il percorso al suo interno!
MrUpsidown

3
SVG viene solitamente utilizzato per icone e altri simboli. Un colore. È solo un percorso, come una lettera in un carattere. Il vantaggio è che puoi facilmente ridimensionarlo, ruotarlo e cambiarne il colore, senza perdere qualità. È una forma vettoriale.
MrUpsidown

1
Questa è stata una delle cose più utili che ho letto quest'anno! Molte grazie
Jonathan La'Fey

2
@MrUpsidown Ma ovviamente SVG funziona bene al di fuori delle mappe - non ha mai avuto problemi lì. Ha a che fare con un problema tecnico nel supporto di Google per SVG nel loro rendering su tela, che può essere disattivato in modo che gli SVG vengano invece inseriti nel DOM. Poi c'è la questione con dimensioni calcolate dei marcatori, che ci sono un paio di proprietà nella realizzazione di indicatori di mappa in grado di forzare il size.I've trovato una soluzione parziale qui: stackoverflow.com/a/30890373/634386
Mike Kormendy

68

Se hai bisogno di un svg completo non solo di un percorso e vuoi che sia modificabile sul lato client (ad esempio cambia testo, nascondi dettagli, ...) puoi utilizzare un 'URL' di dati alternativo con svg incluso:

var svg = '<svg width="400" height="110"><rect width="300" height="100" /></svg>';
icon.url = 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(svg);

JavaScript (Firefox) btoa () viene utilizzato per ottenere la codifica base64 dal testo SVG. Puoi anche utilizzare http://dopiaza.org/tools/datauri/index.php per generare URL di dati di base.

Ecco un esempio completo di jsfiddle :

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
        <script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"></script>
    </head>
    <body>
        <div id="map" style="width: 500px; height: 400px;"></div>
        <script type="text/javascript">
            var map = new google.maps.Map(document.getElementById('map'), {
                zoom: 10,
                center: new google.maps.LatLng(-33.92, 151.25),
                mapTypeId: google.maps.MapTypeId.ROADMAP
            });

            var template = [
                '<?xml version="1.0"?>',
                    '<svg width="26px" height="26px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg">',
                        '<circle stroke="#222" fill="{{ color }}" cx="50" cy="50" r="35"/>',
                    '</svg>'
                ].join('\n');
            var svg = template.replace('{{ color }}', '#800');

            var docMarker = new google.maps.Marker({
                position: new google.maps.LatLng(-33.92, 151.25),
                map: map,
                title: 'Dynamic SVG Marker',
                icon: { url: 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg), scaledSize: new google.maps.Size(20, 20) },
optimized: false
            });

            var docMarker = new google.maps.Marker({
                position: new google.maps.LatLng(-33.95, 151.25),
                map: map,
                title: 'Dynamic SVG Marker',
                icon: { url: 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(svg), scaledSize: new google.maps.Size(20, 20) },
optimized: false
            });
        </script>
    </body>
</html>

Ulteriori informazioni possono essere trovate qui .

Evita la codifica base64:

Per evitare la codifica base64 è possibile sostituire 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(svg)con'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg)

Questo dovrebbe funzionare con i browser moderni fino a IE9. Il vantaggio è che encodeURIComponentè una funzione js predefinita e disponibile in tutti i browser moderni. Potresti anche ottenere collegamenti più piccoli, ma devi testarlo e considerare di usarlo al 'posto del "tuo svg.

Vedi anche Ottimizzazione di SVG negli URI di dati per ulteriori informazioni.

Supporto IE: per supportare i marker SVG in IE sono necessari due piccoli adattamenti come descritto qui: Marker SVG in IE . Ho aggiornato il codice di esempio per supportare IE.


3
Buone informazioni, ma nota rapida che la codifica base64 non è effettivamente necessaria o desiderabile. Puoi invece utilizzare la codifica svg direttamente nell'URI dei dati, come data:image/svg+xml;utf8,. Maggiori informazioni: css-tricks.com/probably-dont-base64-svg
Josh da Qaribou

Hai ragione, sarebbe fantastico se potessimo evitare la codifica base64. Come hai fatto, potresti fornire un esempio? Se aggiungo solo il codice svg all'URI non funziona con alcuni caratteri come #hai usato la codifica URL?
Tom il

Dovrei menzionare che è codificato in utf8; svg è il formato. Il collegamento fornito ha diversi esempi.
Josh da Qaribou

1
Come utilizzare Ruota immagine SVG usando questo?
Somnath Kharat

Non amiamo tutti IE;) Come al solito, richiede del lavoro aggiuntivo per farlo funzionare su tutti i browser. Ho adattato l'esempio per supportare IE, spero che questo aiuti.
Tom

30

So che questo post è un po 'vecchio, ma ho visto così tante cattive informazioni su questo a SO che potrei urlare. Quindi devo solo buttare i miei due centesimi con un approccio completamente diverso che so funziona, poiché lo uso in modo affidabile su molte mappe. Oltre a ciò, credo che l'OP volesse anche la possibilità di ruotare l'indicatore della freccia attorno al punto della mappa, il che è diverso dalla rotazione dell'icona attorno al proprio asse x, y che cambierà il punto in cui l'indicatore della freccia punta sulla mappa.

Innanzitutto, ricorda che stiamo giocando con le mappe di Google e SVG, quindi dobbiamo adattarsi al modo in cui Google distribuisce la sua implementazione di SVG per i marcatori (o in realtà i simboli). Google imposta il suo ancoraggio per l'immagine del marker SVG a 0,0 che NON È l'angolo superiore sinistro del viewBox SVG. Per aggirare questo problema, devi disegnare la tua immagine SVG in modo leggermente diverso per dare a Google quello che vuole ... sì, la risposta è nel modo in cui crei effettivamente il percorso SVG nel tuo editor SVG (Illustrator, Inkscape, ecc. .).

Il primo passo è sbarazzarsi di viewBox. Questo può essere fatto impostando il viewBox nel tuo XML su 0 ... esatto, solo uno zero invece dei soliti quattro argomenti per il viewBox. Questo disattiva la casella di visualizzazione (e sì, questo è semanticamente corretto). Probabilmente noterai che la dimensione della tua immagine salta immediatamente quando lo fai, e questo perché svg non ha più una base (il viewBox) per ridimensionare l'immagine. Quindi creiamo quel riferimento direttamente, impostando la larghezza e l'altezza sul numero effettivo di pixel che desideri che la tua immagine sia nell'editor XML del tuo editor SVG.

Impostando la larghezza e l'altezza dell'immagine SVG nell'editor XML si crea una linea di base per il ridimensionamento dell'immagine e questa dimensione diventa un valore di 1 per le proprietà della scala del marker per impostazione predefinita. Puoi vedere il vantaggio che questo ha per il ridimensionamento dinamico del marker.

Ora che hai la dimensione dell'immagine, sposta l'immagine fino a quando la parte dell'immagine che desideri avere come ancoraggio si trova sulle coordinate 0,0 dell'editor svg. Una volta fatto questo, copia il valore dell'attributo d del percorso svg. Noterai che circa la metà dei numeri sono negativi, il che è il risultato dell'allineamento del punto di ancoraggio per lo 0,0 dell'immagine anziché per il viewBox.

L'utilizzo di questa tecnica ti consentirà di ruotare correttamente il marker, attorno al punto lat e lng sulla mappa. Questo è l'unico modo affidabile per legare il punto sul marker SVG che si desidera alla latitudine e alla longitudine della posizione del marker.

Ho provato a creare un JSFiddle per questo , ma c'è qualche bug nell'implementazione, uno dei motivi per cui non amo così tanto il codice reinterpretato. Quindi, invece, ho incluso di seguito un esempio completamente autonomo che puoi provare, adattare e utilizzare come riferimento. Questo è lo stesso codice che ho provato su JSFiddle che non è riuscito, ma naviga attraverso Firebug senza un piagnucolio.

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport"  content="width=device-width, initial-scale=1" />
    <meta name="author"    content="Drew G. Stimson, Sr. ( Epiphany )" />
    <title>Create Draggable and Rotatable SVG Marker</title>
    <script src="http://maps.googleapis.com/maps/api/js?sensor=false"> </script>
    <style type="text/css">
      #document_body {
        margin:0;
        border: 0;
        padding: 10px;
        font-family: Arial,sans-serif;
        font-size: 14px;
        font-weight: bold;
        color: #f0f9f9;
        text-align: center;
        text-shadow: 1px 1px 1px #000;
        background:#1f1f1f;
      }
      #map_canvas, #rotation_control {
        margin: 1px;
        border:1px solid #000;
        background:#444;
        -webkit-border-radius: 4px;
           -moz-border-radius: 4px;
                border-radius: 4px;
      }
      #map_canvas { 
        width: 100%;
        height: 360px;
      }
      #rotation_control { 
        width: auto;
        padding:5px;
      }
      #rotation_value { 
        margin: 1px;
        border:1px solid #999;
        width: 60px;
        padding:2px;
        font-weight: bold;
        color: #00cc00;
        text-align: center;
        background:#111;
        border-radius: 4px;
      }
</style>

<script type="text/javascript">
  var map, arrow_marker, arrow_options;
  var map_center = {lat:41.0, lng:-103.0};
  var arrow_icon = {
    path: 'M -1.1500216e-4,0 C 0.281648,0 0.547084,-0.13447 0.718801,-0.36481 l 17.093151,-22.89064 c 0.125766,-0.16746 0.188044,-0.36854 0.188044,-0.56899 0,-0.19797 -0.06107,-0.39532 -0.182601,-0.56215 -0.245484,-0.33555 -0.678404,-0.46068 -1.057513,-0.30629 l -11.318243,4.60303 0,-26.97635 C 5.441639,-47.58228 5.035926,-48 4.534681,-48 l -9.06959,0 c -0.501246,0 -0.906959,0.41772 -0.906959,0.9338 l 0,26.97635 -11.317637,-4.60303 c -0.379109,-0.15439 -0.812031,-0.0286 -1.057515,0.30629 -0.245483,0.33492 -0.244275,0.79809 0.0055,1.13114 L -0.718973,-0.36481 C -0.547255,-0.13509 -0.281818,0 -5.7002158e-5,0 Z',
    strokeColor: 'black',
    strokeOpacity: 1,
    strokeWeight: 1,
    fillColor: '#fefe99',
    fillOpacity: 1,
    rotation: 0,
    scale: 1.0
  };

function init(){
  map = new google.maps.Map(document.getElementById('map_canvas'), {
    center: map_center,
    zoom: 4,
    mapTypeId: google.maps.MapTypeId.HYBRID
  });
  arrow_options = {
    position: map_center,
    icon: arrow_icon,
    clickable: false,
    draggable: true,
    crossOnDrag: true,
    visible: true,
    animation: 0,
    title: 'I am a Draggable-Rotatable Marker!' 
  };
  arrow_marker = new google.maps.Marker(arrow_options);
  arrow_marker.setMap(map);
}
function setRotation(){
  var heading = parseInt(document.getElementById('rotation_value').value);
  if (isNaN(heading)) heading = 0;
  if (heading < 0) heading = 359;
  if (heading > 359) heading = 0;
  arrow_icon.rotation = heading;
  arrow_marker.setOptions({icon:arrow_icon});
  document.getElementById('rotation_value').value = heading;
}
</script>
</head>
<body id="document_body" onload="init();">
  <div id="rotation_control">
    <small>Enter heading to rotate marker&nbsp;&nbsp;&nbsp;&nbsp;</small>
    Heading&deg;<input id="rotation_value" type="number" size="3" value="0" onchange="setRotation();" />
    <small>&nbsp;&nbsp;&nbsp;&nbsp;Drag marker to place marker</small>
    </div>
    <div id="map_canvas"></div>
</body>
</html>

Questo è esattamente ciò che fa Google per i suoi pochi simboli disponibili nella classe SYMBOL dell'API di Maps, quindi se questo non ti convince ... Comunque, spero che questo ti aiuti a creare e impostare correttamente un marker SVG per le tue mappe di Google endevours.


2
Bella risposta, ho creato un violino funzionante del tuo codice affinché le persone possano vedere jsfiddle.net/v2pjfp7r
Rob Schmuecker

"<3" Si tratta di informazioni essenziali che dovrebbero far parte della documentazione di Google.
user7653815

12

Sì, puoi utilizzare un file .svg per l'icona proprio come puoi .png o un altro formato di file immagine. Basta impostare l'URL dell'icona nella directory in cui si trova il file .svg. Per esempio:

var icon = {
        url: 'path/to/images/car.svg',
        size: new google.maps.Size(sizeX, sizeY),
        origin: new google.maps.Point(0, 0),
        anchor: new google.maps.Point(sizeX/2, sizeY/2)
};

var marker = new google.maps.Marker({
        position: event.latLng,
        map: map,
        draggable: false,
        icon: icon
});

1
L'oggetto icona che stai mostrando è per un marker standard, non per un marker SVG. Un marker SVG utilizza le proprietà della classe symbol, che vengono quindi assegnate come proprietà icon della classe marker. (vedi oggetto icona MrUpsidown per un corretto riferimento ...)
Epifania

2
Ciò si interromperà anche se l'SVG ha più di un percorso "d" (solitamente associato a più di un livello nell'immagine svg).
Epifania

2
Si noti che il file SVG dovrebbe impostare in modo esplicito le dimensioni dell'icona in questo modo: width="33px" height="50px"- vedi stackoverflow.com/a/21783089/165673
Yarin

10

Le cose stanno andando meglio, adesso puoi usare i file SVG.

        marker = new google.maps.Marker({
            position: {lat: 36.720426, lng: -4.412573},
            map: map,
            draggable: true,
            icon: "img/tree.svg"
        });

1
non consente la rotazione
Matt Westlake

5

Come menzionato da altri in questo thread, non dimenticare di impostare esplicitamente gli attributi di larghezza e altezza nello svg in questo modo:

<svg id="some_id" data-name="some_name" xmlns="http://www.w3.org/2000/svg"
     viewBox="0 0 26 42"
     width="26px" height="42px">

se non lo fai, nessuna manipolazione di js può aiutarti poiché gmaps non avrà un quadro di riferimento e utilizzerà sempre una dimensione standard.

(So ​​che è stato menzionato in alcuni commenti, ma è facile non vederli. Questa informazione mi ha aiutato in vari casi)


1

OK! L'ho fatto presto nel mio sito web, provo due modi per creare l'indicatore della mappa google personalizzato, questo codice di esecuzione che utilizza canvg.js è la migliore compatibilità per il browser. Il codice commentato non supporta IE11 attualmente.

var marker;
var CustomShapeCoords = [16, 1.14, 21, 2.1, 25, 4.2, 28, 7.4, 30, 11.3, 30.6, 15.74, 25.85, 26.49, 21.02, 31.89, 15.92, 43.86, 10.92, 31.89, 5.9, 26.26, 1.4, 15.74, 2.1, 11.3, 4, 7.4, 7.1, 4.2, 11, 2.1, 16, 1.14];

function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 13,
    center: {
      lat: 59.325,
      lng: 18.070
    }
  });
  var markerOption = {
    latitude: 59.327,
    longitude: 18.067,
    color: "#" + "000",
    text: "ha"
  };
  marker = createMarker(markerOption);
  marker.setMap(map);
  marker.addListener('click', changeColorAndText);
};

function changeColorAndText() {
  var iconTmpObj = createSvgIcon( "#c00", "ok" );
  marker.setOptions( {
                icon: iconTmpObj
            } );
};

function createMarker(options) {
  //IE MarkerShape has problem
  var markerObj = new google.maps.Marker({
    icon: createSvgIcon(options.color, options.text),
    position: {
      lat: parseFloat(options.latitude),
      lng: parseFloat(options.longitude)
    },
    draggable: false,
    visible: true,
    zIndex: 10,
    shape: {
      coords: CustomShapeCoords,
      type: 'poly'
    }
  });

  return markerObj;
};

function createSvgIcon(color, text) {
  var div = $("<div></div>");

  var svg = $(
    '<svg width="32px" height="43px"  viewBox="0 0 32 43" xmlns="http://www.w3.org/2000/svg">' +
    '<path style="fill:#FFFFFF;stroke:#020202;stroke-width:1;stroke-miterlimit:10;" d="M30.6,15.737c0-8.075-6.55-14.6-14.6-14.6c-8.075,0-14.601,6.55-14.601,14.6c0,4.149,1.726,7.875,4.5,10.524c1.8,1.801,4.175,4.301,5.025,5.625c1.75,2.726,5,11.976,5,11.976s3.325-9.25,5.1-11.976c0.825-1.274,3.05-3.6,4.825-5.399C28.774,23.813,30.6,20.012,30.6,15.737z"/>' +
    '<circle style="fill:' + color + ';" cx="16" cy="16" r="11"/>' +
    '<text x="16" y="20" text-anchor="middle" style="font-size:10px;fill:#FFFFFF;">' + text + '</text>' +
    '</svg>'
  );
  div.append(svg);

  var dd = $("<canvas height='50px' width='50px'></cancas>");

  var svgHtml = div[0].innerHTML;

  canvg(dd[0], svgHtml);

  var imgSrc = dd[0].toDataURL("image/png");
  //"scaledSize" and "optimized: false" together seems did the tricky ---IE11  &&  viewBox influent IE scaledSize
  //var svg = '<svg width="32px" height="43px"  viewBox="0 0 32 43" xmlns="http://www.w3.org/2000/svg">'
  //    + '<path style="fill:#FFFFFF;stroke:#020202;stroke-width:1;stroke-miterlimit:10;" d="M30.6,15.737c0-8.075-6.55-14.6-14.6-14.6c-8.075,0-14.601,6.55-14.601,14.6c0,4.149,1.726,7.875,4.5,10.524c1.8,1.801,4.175,4.301,5.025,5.625c1.75,2.726,5,11.976,5,11.976s3.325-9.25,5.1-11.976c0.825-1.274,3.05-3.6,4.825-5.399C28.774,23.813,30.6,20.012,30.6,15.737z"/>'
  //    + '<circle style="fill:' + color + ';" cx="16" cy="16" r="11"/>'
  //    + '<text x="16" y="20" text-anchor="middle" style="font-size:10px;fill:#FFFFFF;">' + text + '</text>'
  //    + '</svg>';
  //var imgSrc = 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg);

  var iconObj = {
    size: new google.maps.Size(32, 43),
    url: imgSrc,
    scaledSize: new google.maps.Size(32, 43)
  };

  return iconObj;
};
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Your Custom Marker </title>
  <style>
    /* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
    #map {
      height: 100%;
    }
    /* Optional: Makes the sample page fill the window. */
    html,
    body {
      height: 100%;
      margin: 0;
      padding: 0;
    }
  </style>
</head>

<body>
  <div id="map"></div>
    <script src="https://canvg.github.io/canvg/canvg.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script async defer src="https://maps.googleapis.com/maps/api/js?callback=initMap"></script>
</body>

</html>


-4

Devi passare optimized: false.

Per esempio

var img = { url: 'img/puff.svg', scaledSide: new google.maps.Size(5, 5) };
new google.maps.Marker({position: this.mapOptions.center, map: this.map, icon: img, optimized: false,});

Senza passare optimized: false, il mio svg è apparso come un'immagine statica.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.