Comment utiliser les marqueurs SVG dans l'API Google Maps v3

91

Puis-je utiliser mon image.svg convertie comme icône google map. J'étais en train de convertir mon image png en svg et je souhaite l'utiliser comme un symbole de carte google qui peut être pivoté. J'ai déjà essayé d'utiliser le symbole de google map mais je veux avoir une icône comme voiture, homme, etc ... C'est pourquoi j'ai converti mes quelques fichiers png en svg, tout comme cet exemple de site qu'est-ce qu'il utilise pour ces http: / /www.goprotravelling.com/

jemz
la source
1
Pour ceux qui recherchent cette question similaire: une solution partielle compatible IE 9+ ici: stackoverflow.com/a/30890373/634386 placera un SVG dans le DOM plutôt que sur le canevas afin que vous puissiez manipuler avec CSS3 après (si vous ' cherchez à faire pivoter cet élément spécifiquement à la volée).
Mike Kormendy

Réponses:

144

Vous pouvez rendre votre icône en utilisant la notation SVG Path .

Consultez la documentation Google pour plus d'informations.

Voici un exemple de 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
});

Voici un exemple de travail sur la façon d'afficher et de mettre à l'échelle une icône SVG de marqueur:

Démo JSFiddle

Éditer:

Un autre exemple ici avec une icône complexe:

Démo JSFiddle

Modifier 2:

Et voici comment vous pouvez avoir un fichier SVG comme icône:

Démo JSFiddle

MrUpsidown
la source
, il est très difficile de créer un svg de voiture.
jemz
Avez-vous une image SVG de cette voiture que vous voulez? Ensuite, ouvrez-le simplement avec un éditeur de texte et trouvez le chemin d'accès!
MrUpsidown
3
SVG est généralement utilisé pour les icônes et autres symboles. Une couleur. C'est juste un chemin, comme une lettre dans une police. L'avantage est que vous pouvez facilement le mettre à l'échelle, le faire pivoter et changer sa couleur, sans perte de qualité. C'est une forme vectorielle.
MrUpsidown
1
C'était l'une des choses les plus utiles que j'ai lues cette année! Merci beaucoup
Jonathan La'Fey
2
@MrUpsidown Mais bien sûr, SVG fonctionne bien en dehors des cartes - il n'y a jamais eu de problème. Cela a à voir avec un problème dans la prise en charge par Google du SVG dans leur rendu de canevas - qui peut être désactivé pour que les SVG soient insérés dans le DOM à la place. Ensuite, il y a le problème avec les tailles calculées des marqueurs, qu'il y a quelques propriétés dans l'implémentation des marqueurs de carte qui peuvent forcer la taille.J'ai trouvé une solution partielle ici: stackoverflow.com/a/30890373/634386
Mike Kormendy
68

Si vous avez besoin d'un svg complet, pas seulement d'un chemin et que vous voulez qu'il soit modifiable côté client (par exemple, changer le texte, masquer les détails, ...), vous pouvez utiliser une autre 'URL' de données avec svg inclus:

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 () est utilisé pour obtenir l'encodage base64 à partir du texte SVG. Vous pouvez également utiliser http://dopiaza.org/tools/datauri/index.php pour générer des URL de données de base.

Voici un exemple complet de 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>

Des informations supplémentaires peuvent être trouvées ici .

Évitez l'encodage base64:

Afin d'éviter l'encodage base64, vous pouvez remplacer 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(svg)par'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg)

Cela devrait fonctionner avec les navigateurs modernes jusqu'à IE9. L'avantage est qu'il encodeURIComponents'agit d'une fonction js par défaut et disponible dans tous les navigateurs modernes. Vous pouvez également obtenir des liens plus petits, mais vous devez le tester et envisager de l'utiliser à la 'place de "votre svg.

Voir également Optimiser les SVG dans les URI de données pour plus d'informations.

Support IE: Afin de prendre en charge les marqueurs SVG dans IE, il faut deux petites adaptations comme décrit ici: Les marqueurs SVG dans IE . J'ai mis à jour l'exemple de code pour prendre en charge IE.

À M
la source
3
Bonne information, mais notez rapidement que l'encodage base64 n'est ni nécessaire ni souhaitable. Vous pouvez utiliser l'encodage svg directement dans l'URI des données à la place, comme data:image/svg+xml;utf8,. Plus d'informations: css-tricks.com/probably-dont-base64-svg
Josh de Qaribou
Vous avez raison, ce serait formidable si nous pouvions éviter le codage base64. Comment as-tu fait pourrais-tu donner un exemple? Si j'ajoute simplement le code svg à l'URI, cela ne fonctionne pas avec certains caractères, comme #avez-vous utilisé le codage d'URL?
Tom
Je devrais mentionner qu'il est encodé en utf8; svg est le format. Le lien fourni a plusieurs exemples.
Josh de Qaribou
1
Comment utiliser la rotation de l'image svg en utilisant ceci?
Somnath Kharat
N'aimons-nous pas tous IE;) Comme d'habitude, il faut un travail supplémentaire pour le faire fonctionner sur tous les navigateurs. J'ai adapté l'exemple pour soutenir IE, j'espère que cela aide.
Tom
30

Je sais que ce post est un peu vieux, mais j'ai vu tellement de mauvaises informations à ce sujet à SO que je pourrais crier. Donc, je dois juste jeter mes deux cents avec une approche totalement différente qui, je sais, fonctionne, car je l'utilise de manière fiable sur de nombreuses cartes. En plus de cela, je pense que l'OP voulait également la possibilité de faire pivoter le marqueur de flèche autour du point de la carte, ce qui est différent de la rotation de l'icône autour de son propre axe x, y qui changera l'endroit où le marqueur de flèche pointe sur la carte.

Tout d'abord, rappelez-vous que nous jouons avec Google maps et SVG, nous devons donc nous adapter à la manière dont Google déploie son implémentation de SVG pour les marqueurs (ou en fait les symboles). Google fixe son ancre pour l'image du marqueur SVG à 0,0, qui N'EST PAS le coin supérieur gauche de la zone de visualisation SVG. Pour contourner cela, vous devez dessiner votre image SVG un peu différemment pour donner à Google ce qu'il veut ... oui la réponse est dans la façon dont vous créez réellement le chemin SVG dans votre éditeur SVG (Illustrator, Inkscape, etc. .).

La première étape consiste à se débarrasser de la viewBox. Cela peut être fait en définissant la viewBox dans votre XML sur 0 ... c'est vrai, juste un zéro au lieu des quatre arguments habituels pour la viewBox. Cela désactive la zone d'affichage (et oui, c'est sémantiquement correct). Vous remarquerez probablement que la taille de votre image saute immédiatement lorsque vous faites cela, et c'est parce que le svg n'a plus de base (la viewBox) pour redimensionner l'image. Nous créons donc cette référence directement, en définissant la largeur et la hauteur sur le nombre réel de pixels que vous souhaitez que votre image soit dans l'éditeur XML de votre éditeur SVG.

En définissant la largeur et la hauteur de l'image svg dans l'éditeur XML, vous créez une ligne de base pour la mise à l'échelle de l'image, et cette taille devient une valeur de 1 pour les propriétés d'échelle du marqueur par défaut. Vous pouvez voir l'avantage que cela présente pour la mise à l'échelle dynamique du marqueur.

Maintenant que votre image est dimensionnée, déplacez l'image jusqu'à ce que la partie de l'image que vous souhaitez avoir comme ancre se trouve au-dessus des coordonnées 0,0 de l'éditeur svg. Une fois que vous avez fait cela, copiez la valeur de l' attribut d du chemin svg. Vous remarquerez qu'environ la moitié des nombres sont négatifs, ce qui est le résultat de l'alignement de votre point d'ancrage pour le 0,0 de l'image au lieu de la viewBox.

L'utilisation de cette technique vous permettra ensuite de faire pivoter correctement le marqueur, autour du point lat et lng sur la carte. C'est le seul moyen fiable de lier le point du marqueur svg que vous souhaitez à la lat et à la longueur de l'emplacement du marqueur.

J'ai essayé de créer un JSFiddle pour cela , mais il y a un bogue dans l'implémentation, l'une des raisons pour lesquelles je n'aime pas trop le code réinterprété. Au lieu de cela, j'ai inclus ci-dessous un exemple entièrement autonome que vous pouvez essayer, adapter et utiliser comme référence. C'est le même code que j'ai essayé chez JSFiddle qui a échoué, mais il navigue à travers Firebug sans un gémissement.

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

C'est exactement ce que Google fait pour ses propres symboles disponibles dans la classe SYMBOL de l'API Maps, donc si cela ne vous convainc pas ... Quoi qu'il en soit, j'espère que cela vous aidera à créer et configurer correctement un marqueur SVG pour vos cartes Google endevours.

Épiphanie
la source
2
Bonne réponse, j'ai fait un violon fonctionnel de votre code pour que les gens puissent voir jsfiddle.net/v2pjfp7r
Rob Schmuecker
"<3" Ce sont des informations essentielles qui devraient faire partie de la documentation Google.
user7653815
12

Oui, vous pouvez utiliser un fichier .svg pour l'icône comme vous pouvez le faire .png ou un autre format de fichier image. Définissez simplement l'url de l'icône sur le répertoire où se trouve le fichier .svg. Par exemple:

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
});
LaPersonneSansC
la source
1
L'objet icône que vous affichez est pour un marqueur standard, pas un marqueur SVG. Un marqueur svg utilise les propriétés de la classe de symboles, qui sont ensuite affectées comme propriété d'icône de la classe de marqueur. (voir l'objet icône MrUpsidown pour une référence correcte ...)
Epiphany
2
Cela cassera également si le SVG a plus d'un chemin «d» (généralement associé à plus d'un calque dans l'image svg).
Épiphanie
2
Notez que votre fichier svg doit définir explicitement les dimensions de l'icône comme width="33px" height="50px"
suit
10

Les choses vont mieux, vous pouvez maintenant utiliser des fichiers SVG.

        marker = new google.maps.Marker({
            position: {lat: 36.720426, lng: -4.412573},
            map: map,
            draggable: true,
            icon: "img/tree.svg"
        });
gengns
la source
1
ne permet pas la rotation
Matt Westlake
5

Comme mentionné par d'autres dans ce fil, n'oubliez pas de définir explicitement les attributs width et height dans le svg comme suit:

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

si vous ne le faites pas, aucune manipulation js ne peut vous aider car gmaps n'aura pas de cadre de référence et utilisera toujours une taille standard.

(Je sais que cela a été mentionné dans certains commentaires, mais ils sont faciles à manquer. Ces informations m'ont aidé dans divers cas)

Larzan
la source
1

D'ACCORD! Je l'ai fait bientôt dans mon site Web, j'essaie de deux façons de créer le marqueur de carte google personnalisé, ce code d'exécution utilise canvg.js est la meilleure compatibilité pour le navigateur.Le code commenté n'est pas compatible avec IE11 de manière actuelle.

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>

Soleil
la source
-4

Vous devez réussir optimized: false.

Par exemple

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

Sans passer optimized: false, mon svg est apparu comme une image statique.

Jeremy Eaton
la source