Verwendung von SVG-Markern in Google Maps API v3


90

Kann ich meine konvertierte image.svg als Google Map-Symbol verwenden? Ich habe mein PNG-Bild in SVG konvertiert und möchte dieses Symbol wie das Google Map-Symbol verwenden, das gedreht werden kann. Ich habe bereits versucht, das Google Map-Symbol zu verwenden, aber ich möchte ein Symbol wie Auto, Mann usw. haben. Deshalb habe ich meine PNG-Dateien in SVG konvertiert, genau wie diese Beispielseite, was er für diese http: / verwendet /www.goprotravelling.com/


1
Für diejenigen, die nach dieser ähnlichen Frage suchen: Eine teilweise IE 9+ -kompatible Lösung hier: stackoverflow.com/a/30890373/634386 platziert eine SVG- Datei im DOM anstatt auf der Zeichenfläche , damit Sie sie anschließend mit CSS3 bearbeiten können (falls Sie dies tun). Ich möchte dieses Element speziell im laufenden Betrieb drehen.
Mike Kormendy

Antworten:


143

Sie können Ihr Symbol mit der SVG-Pfadnotation rendern .

Weitere Informationen finden Sie in der Google-Dokumentation .

Hier ist ein grundlegendes Beispiel:

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

Hier ist ein Arbeitsbeispiel zum Anzeigen und Skalieren eines SVG-Markierungssymbols:

JSFiddle-Demo

Bearbeiten:

Ein weiteres Beispiel hier mit einem komplexen Symbol:

JSFiddle-Demo

Bearbeiten 2:

Und so können Sie eine SVG-Datei als Symbol haben:

JSFiddle-Demo


Es ist sehr schwierig, Auto-SVG zu machen.
Jemz

Haben Sie ein SVG-Bild des gewünschten Autos? Dann öffnen Sie es einfach mit einem Texteditor und finden den Pfad darin!
MrUpsidown

3
SVG wird normalerweise für Symbole und andere Symbole verwendet. Eine Farbe. Es ist nur ein Pfad, wie ein Buchstabe in einer Schriftart. Der Vorteil ist, dass Sie es einfach skalieren, drehen und seine Farbe ändern können, ohne an Qualität zu verlieren. Es ist eine Vektorform.
MrUpsidown

1
Das war eines der nützlichsten Dinge, die ich dieses Jahr gelesen habe! Vielen Dank
Jonathan La'Fey

2
@ MrUpsidown Aber natürlich funktioniert SVG auch außerhalb von Karten einwandfrei - hatte dort nie ein Problem. Dies hat mit einem Fehler in der Unterstützung von Google für SVG beim Canvas-Rendering zu tun. Dieser Fehler kann deaktiviert werden, sodass SVGs stattdessen in das DOM eingefügt werden. Dann gibt es das Problem mit den berechneten Größen der Markierungen. In der Implementierung gibt es einige Eigenschaften für Kartenmarkierungen, die die Größe erzwingen können. Ich habe hier eine Teillösung gefunden: stackoverflow.com/a/30890373/634386
Mike Kormendy

68

Wenn Sie eine vollständige SVG-Datei benötigen, die nicht nur einen Pfad enthält und auf Clientseite geändert werden soll (z. B. Text ändern, Details ausblenden, ...), können Sie eine alternative Daten-URL mit der enthaltenen SVG-Datei verwenden:

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 () wird verwendet, um die base64-Codierung aus dem SVG-Text abzurufen. Sie können auch http://dopiaza.org/tools/datauri/index.php verwenden , um Basisdaten-URLs zu generieren.

Hier ist ein vollständiges Beispiel 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>

Weitere Informationen finden Sie hier .

Vermeiden Sie die Base64-Codierung:

Um zu vermeiden , Base64 - Codierung Sie ersetzen können 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(svg)mit'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg)

Dies sollte mit modernen Browsern bis hin zu IE9 funktionieren. Der Vorteil ist, dass encodeURIComponentes sich um eine Standard-js-Funktion handelt, die in allen modernen Browsern verfügbar ist. Möglicherweise erhalten Sie auch kleinere Links, aber Sie müssen dies testen und in Betracht ziehen, es 'anstelle "Ihres SVG zu verwenden.

Weitere Informationen finden Sie unter Optimieren von SVGs in Daten-URIs .

IE-Unterstützung: Um SVG-Marker im IE zu unterstützen, sind zwei kleine Anpassungen erforderlich, wie hier beschrieben: SVG-Marker im IE . Ich habe den Beispielcode aktualisiert, um IE zu unterstützen.


3
Gute Infos, aber schnell zu beachten, dass die Base64-Codierung eigentlich nicht notwendig oder wünschenswert ist. Sie können die SVG-Codierung stattdessen direkt in der Daten-URI verwenden data:image/svg+xml;utf8,. Weitere Informationen: css-tricks.com/probably-dont-base64-svg
Josh aus Qaribou

Sie haben Recht, es wäre großartig, wenn wir die Base64-Codierung vermeiden könnten. Wie haben Sie es gemacht, könnten Sie ein Beispiel geben? Wenn ich nur den SVG-Code zum URI hinzufüge, funktioniert dies mit einigen Zeichen nicht. Haben #Sie die URL-Codierung verwendet?
Tom

Ich sollte erwähnen, dass es utf8-codiert ist. svg ist das Format. Der bereitgestellte Link enthält mehrere Beispiele.
Josh aus Qaribou

1
Wie verwende ich das Drehen eines SVG-Bildes?
Somnath Kharat

Lieben wir nicht alle IE;) Wie üblich erfordert es einige zusätzliche Arbeit, damit es in allen Browsern funktioniert. Ich habe das Beispiel angepasst, um IE zu unterstützen, hoffe, das hilft.
Tom

29

Ich weiß, dass dieser Beitrag etwas alt ist, aber ich habe bei SO so viele schlechte Informationen darüber gesehen, dass ich schreien könnte. Also muss ich meine zwei Cent mit einem ganz anderen Ansatz einwerfen, von dem ich weiß, dass er funktioniert, da ich ihn auf vielen Karten zuverlässig verwende. Abgesehen davon glaube ich, dass das OP die Möglichkeit haben wollte, die Pfeilmarkierung auch um den Kartenpunkt zu drehen, was sich von der Drehung des Symbols um seine eigene x-, y-Achse unterscheidet, die sich ändert, wohin die Pfeilmarkierung auf der Karte zeigt.

Denken Sie zunächst daran, dass wir mit Google Maps und SVG spielen. Daher müssen wir die Art und Weise berücksichtigen, in der Google die Implementierung von SVG für Marker (oder tatsächlich Symbole) bereitstellt. Google setzt seinen Anker für das SVG-Markierungsbild auf 0,0, was NICHT die obere linke Ecke der SVG-Ansichtsbox ist. Um dies zu umgehen, müssen Sie Ihr SVG-Bild etwas anders zeichnen, um Google das zu geben, was es will ... Ja, die Antwort liegt in der Art und Weise, wie Sie den SVG-Pfad in Ihrem SVG-Editor (Illustrator, Inkscape usw.) erstellen. .).

Der erste Schritt besteht darin, die viewBox zu entfernen. Dies kann erreicht werden, indem Sie die viewBox in Ihrem XML auf 0 setzen ... das ist richtig, nur eine Null anstelle der üblichen vier Argumente für die viewBox. Dadurch wird das Ansichtsfeld deaktiviert (und ja, dies ist semantisch korrekt). Sie werden wahrscheinlich sofort bemerken, dass die Größe Ihres Bildsprungs sofort springt, und das liegt daran, dass das SVG keine Basis (die ViewBox) mehr hat, um das Bild zu skalieren. Daher erstellen wir diese Referenz direkt, indem wir die Breite und Höhe auf die tatsächliche Anzahl der Pixel einstellen, die Ihr Bild im XML-Editor Ihres SVG-Editors haben soll.

Durch Festlegen der Breite und Höhe des SVG-Bilds im XML-Editor erstellen Sie eine Grundlinie für die Skalierung des Bildes. Diese Größe wird standardmäßig für die Eigenschaften der Markierungsskalierung auf den Wert 1 gesetzt. Sie sehen den Vorteil, den dies für die dynamische Skalierung des Markers hat.

Nachdem Sie die Bildgröße festgelegt haben, verschieben Sie das Bild, bis der Teil des Bildes, den Sie als Anker verwenden möchten, über den 0,0-Koordinaten des SVG-Editors liegt. Sobald Sie dies getan haben, kopieren Sie den Wert des Attributs d des SVG-Pfads. Sie werden feststellen, dass etwa die Hälfte der Zahlen negativ ist. Dies ist das Ergebnis der Ausrichtung Ihres Ankerpunkts auf 0,0 des Bildes anstelle der Ansichtsbox.

Mit dieser Technik können Sie den Marker dann korrekt um den Lat- und Lng-Punkt auf der Karte drehen. Dies ist die einzige zuverlässige Methode, um den gewünschten Punkt auf dem SVG-Marker an den Lat und Long der Markerposition zu binden.

Ich habe versucht, eine JSFiddle dafür zu erstellen , aber es gibt einen Fehler in der Implementierung, einer der Gründe, warum ich neu interpretierten Code nicht so mag. Stattdessen habe ich unten ein vollständig eigenständiges Beispiel eingefügt, das Sie ausprobieren, anpassen und als Referenz verwenden können. Dies ist derselbe Code, den ich bei JSFiddle ausprobiert habe und der fehlgeschlagen ist, der jedoch ohne Wimmern durch Firebug segelt.

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

Dies ist genau das, was Google für seine eigenen Symbole tut, die in der SYMBOL-Klasse der Maps-API verfügbar sind. Wenn Sie das also nicht überzeugt ... Ich hoffe, dies hilft Ihnen dabei, einen SVG-Marker für richtig zu erstellen und einzurichten Ihre Google Maps endevours.


2
Schöne Antwort, ich habe eine funktionierende Geige aus Ihrem Code gemacht, damit die Leute jsfiddle.net/v2pjfp7r
Rob

"<3" Dies sind wichtige Informationen, die Teil der Google-Dokumentation sein sollten.
user7653815

11

Ja, Sie können eine .svg-Datei für das Symbol verwenden, genau wie Sie .png oder ein anderes Bilddateiformat. Stellen Sie einfach die URL des Symbols auf das Verzeichnis ein, in dem sich die SVG-Datei befindet. Beispielsweise:

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
Das Symbolobjekt, das Sie anzeigen, ist für einen Standardmarker und nicht für einen SVG-Marker. Ein SVG-Marker verwendet Eigenschaften der Symbolklasse, die dann als Symboleigenschaft der Markerklasse zugewiesen werden. (Eine korrekte Referenz finden Sie im MrUpsidown-Symbolobjekt ...)
Epiphany

2
Dies wird auch unterbrochen, wenn die SVG mehr als einen 'd'-Pfad hat (normalerweise mit mehr als einer Ebene im SVG-Bild verknüpft).
Dreikönigstag

2
Beachten Sie, dass Ihre SVG-Datei die Abmessungen des Symbols explizit wie folgt festlegen sollte : width="33px" height="50px"- Siehe stackoverflow.com/a/21783089/165673
Yarin

10

Die Dinge laufen besser, jetzt können Sie SVG-Dateien verwenden.

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

1
erlaubt keine Rotation
Matt Westlake

5

Wie von anderen in diesem Thread erwähnt, vergessen Sie nicht, die Attribute width und height im svg explizit wie folgt festzulegen:

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

Wenn Sie dies nicht tun, kann Ihnen keine js-Manipulation helfen, da gmaps keinen Referenzrahmen haben und immer eine Standardgröße verwenden.

(Ich weiß, dass es in einigen Kommentaren erwähnt wurde, aber sie sind leicht zu übersehen. Diese Informationen haben mir in verschiedenen Fällen geholfen.)


1

OK! Ich habe dies bald in meinem Web getan. Ich versuche auf zwei Arten, den benutzerdefinierten Google Map-Marker zu erstellen. Dieser Ausführungscode mit canvg.js ist die beste Kompatibilität für den Browser. Der auskommentierte Code unterstützt IE11 derzeit nicht.

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

Du musst bestehen optimized: false .

Z.B

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

Ohne zu bestehen optimized: false, erschien mein SVG als statisches Bild.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.