web-dev-qa-db-fra.com

Comment utiliser les marqueurs SVG dans Google Maps API v3

Puis-je utiliser mon image.svg converti comme icône de carte Google. Je convertissais mon image png en svg et je souhaite utiliser ce symbole google map qui peut être pivoté. J'ai déjà essayé d'utiliser le symbole Google Map mais je veux une icône comme voiture, homme, etc. C'est pourquoi j'ai converti certains fichiers png en svg, tout comme cet exemple de site que fait-il pour ces http: //www.goprotravelling.com/

80
jemz

Vous pouvez rendre votre icône en utilisant notation de chemin SVG .

Voir 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 redimensionner une icône SVG de marqueur:

démo JSFiddle

Modifier:

Un autre exemple ici avec une icône complexe:

démo JSFiddle

Éditer 2:

Et voici comment vous pouvez avoir un fichier SVG sous forme d’icône:

démo JSFiddle

121
MrUpsidown

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, modifier le texte, masquer les détails, ...), vous pouvez utiliser une autre "URL" de données avec le 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 le codage base64 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 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 le codage en base64:

Afin d'éviter l'encodage en 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 que encodeURIComponent est 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 d'utiliser ' au lieu de " dans votre svg.

Voir aussi Optimisation des 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: Marqueurs SVG dans IE . J'ai mis à jour le code d'exemple pour prendre en charge IE.

53
Tom

Je sais que ce message est un peu vieux, mais j’ai vu tellement de mauvaises informations à ce sujet à SO que je pouvais crier. Donc, je dois juste mettre mes deux sous avec une approche complètement différente que je sais que fonctionne, car je l'utilise de manière fiable sur de nombreuses cartes. En plus de cela, je pense que le PO voulait pouvoir faire pivoter la flèche autour du point de la carte, ce qui est différent de la rotation de l'icône autour de ses propres axes x, y, ce qui changera l'emplacement de la flèche sur la carte.

Premièrement, rappelez-vous que nous jouons avec Google maps et SVG. Nous devons donc adapter la manière dont Google déploie la mise en œuvre de SVG pour les marqueurs (ou les symboles). Google définit son ancre pour l'image du marqueur SVG à 0,0, ce qui IS PAS le coin supérieur gauche de la vue SVG. Pour résoudre ce problème, vous devez dessiner votre image SVG un peu différemment pour donner à Google ce qu'il veut ... oui, la réponse est dans la manière dont vous créez le chemin SVG dans votre éditeur SVG (Illustrator, Inkscape, etc.). .).

La première étape consiste à supprimer le viewBox. Cela peut être fait en définissant le viewBox dans votre XML sur 0 ... c'est vrai, juste un zéro au lieu des quatre arguments habituels pour le viewBox. Cela désactive la vue (et oui, c’est sémantiquement correct). Vous remarquerez probablement que la taille de votre image saute immédiatement lorsque vous le faites, car le fichier svg n'a plus de base (le 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 pour votre image 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. Cette taille devient par défaut la valeur 1 pour les propriétés d'échelle du marqueur. Vous pouvez voir l'avantage que cela présente pour la mise à l'échelle dynamique du marqueur.

Maintenant que votre image est redimensionnée, déplacez-la jusqu'à ce que la partie de l'image que vous souhaitez avoir comme ancrage dépasse les coordonnées 0,0 de l'éditeur de svg. Une fois cette opération effectuée, copiez la valeur de l'attribut d du chemin svg. Vous remarquerez qu'environ la moitié des nombres sont négatifs, ce qui résulte de l'alignement de votre point d'ancrage pour le 0,0 de l'image au lieu du viewBox.

En utilisant cette technique, vous pourrez alors faire pivoter le marqueur correctement, autour des points de latitude et de longitude sur la carte. C'est le seul moyen fiable de lier le point sur le marqueur svg que vous voulez au dernier et long de l'emplacement du marqueur.

J'ai essayé de faire un JSFiddle pour cela , mais il y a un bug dans son implémentation, l'une des raisons pour lesquelles je ne suis pas si friands de code réinterprété. Au lieu de cela, j’ai inclus un exemple entièrement autonome ci-dessous 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 dans 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 SYMBOLE 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 EndVours.

26
Epiphany

Oui, vous pouvez utiliser un fichier .svg pour l'icône, tout comme vous pouvez utiliser le format .png ou un autre format de fichier image. Il suffit de définir l’URL de l’icône dans 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
});
11
ThePersonWithoutC

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

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

Comme mentionné par d'autres dans ce fil, n'oubliez pas de définissez explicitement la largeur et la hauteur attributs 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 de JS ne peut vous aider, car les cartes graphiques n'auront pas de cadre de référence et utiliseront toujours une taille standard.

(je sais que cela a été mentionné dans certains commentaires, mais ils sont faciles à manquer. Cette information m'a aidé dans divers cas)

4
Larzan

D'ACCORD! C’est ce que j’ai fait bientôt dans mon site Web. J’ai essayé de deux manières de créer le marqueur de carte google personnalisé. Ce code d’exécution, canvg.js, est la meilleure compatibilité pour les navigateurs.

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