Jak korzystać ze znaczników SVG w Google Maps API v3

91

Czy mogę użyć przekonwertowanego pliku image.svg jako ikony mapy Google. Konwertowałem mój obraz png na svg i chcę użyć tego symbolu mapy google, który można obracać. Próbowałem już użyć symbolu mapy google, ale chcę mieć ikonę, taką jak samochód, człowiek, itp ... Dlatego przekonwertowałem niektóre pliki png na svg, tak jak w tej przykładowej witrynie, czego używa do tych http: / /www.goprotravelling.com/

jemz
źródło
1
Dla tych, którzy szukają tego podobnego pytania: tutaj rozwiązanie częściowo zgodne z IE 9+: stackoverflow.com/a/30890373/634386 umieści plik SVG w DOM zamiast na płótnie, aby można było manipulować za pomocą CSS3 po (jeśli ' staram się obrócić ten element specjalnie w locie).
Mike Kormendy,

Odpowiedzi:

145

Możesz renderować swoją ikonę za pomocą notacji SVG Path .

Więcej informacji można znaleźć w dokumentacji Google .

Oto podstawowy przykład:

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

Oto działający przykład, jak wyświetlić i skalować ikonę SVG znacznika:

Demo JSFiddle

Edytować:

Kolejny przykład ze złożoną ikoną:

Demo JSFiddle

Edycja 2:

A oto jak możesz mieć plik SVG jako ikonę:

Demo JSFiddle

MrUpsidown
źródło
, bardzo trudno jest zrobić svg samochodu.
jemz
Czy masz obraz SVG tego samochodu? Następnie otwórz go za pomocą edytora tekstu i znajdź w nim ścieżkę!
MrUpsidown
3
SVG jest zwykle używany do ikon i innych symboli. Jeden kolor. To tylko ścieżka, jak litera w czcionce. Zaletą jest to, że można go łatwo skalować, obracać i zmieniać jego kolor, bez utraty jakości. To kształt wektorowy.
MrUpsidown
1
To była jedna z najbardziej przydatnych rzeczy, które przeczytałem w tym roku! Wielkie dzięki
Jonathan La'Fey
2
@MrUpsidown Ale oczywiście SVG działa dobrze poza mapami - nigdy nie było tam problemu. Ma to związek z usterką we wsparciu Google dla SVG w ich renderowaniu na płótnie - które można wyłączyć, aby zamiast tego SVG były wstawiane do DOM. Następnie pojawia się problem z obliczonymi rozmiarami znaczników, których w implementacji jest kilka właściwości znaczników mapy, które mogą wymusić rozmiar.Znalazłem częściowe rozwiązanie tutaj: stackoverflow.com/a/30890373/634386
Mike Kormendy
68

Jeśli potrzebujesz pełnego pliku SVG, a nie tylko ścieżki, i chcesz, aby można go było modyfikować po stronie klienta (np. Zmienić tekst, ukryć szczegóły, ...), możesz użyć alternatywnego adresu URL danych z dołączonym plikiem SVG:

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 () jest używany do uzyskania kodowania base64 z tekstu SVG. Możesz również użyć http://dopiaza.org/tools/datauri/index.php do generowania podstawowych adresów URL danych.

Oto pełny przykład 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>

Dodatkowe informacje można znaleźć tutaj .

Unikaj kodowania base64:

W celu uniknięcia base64 kodowania można zastąpić 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(svg)z'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg)

To powinno działać z nowoczesnymi przeglądarkami aż do IE9. Zaletą jest to, że encodeURIComponentjest to domyślna funkcja js i dostępna we wszystkich nowoczesnych przeglądarkach. Możesz również otrzymać mniejsze linki, ale musisz to przetestować i rozważyć użycie 'zamiast "w swoim svg.

Aby uzyskać dodatkowe informacje, zobacz także Optymalizacja plików SVG w identyfikatorach URI danych .

Obsługa IE: Aby obsługiwać markery SVG w IE, potrzebne są dwie małe adaptacje, jak opisano tutaj: Markery SVG w IE . Zaktualizowałem przykładowy kod do obsługi IE.

Tomek
źródło
3
Dobra informacja, ale szybko zauważ, że kodowanie base64 nie jest w rzeczywistości konieczne ani pożądane. Zamiast tego możesz użyć kodowania svg bezpośrednio w identyfikatorze URI danych, na przykład data:image/svg+xml;utf8,. Więcej informacji: css-tricks.com/probably-dont-base64-svg
Josh z Qaribou
Masz rację, byłoby wspaniale, gdybyśmy mogli uniknąć kodowania base64. Jak to zrobiłeś, czy możesz podać przykład? Jeśli po prostu dodam kod svg do identyfikatora URI, to nie działa z niektórymi znakami, tak #jak używałeś kodowania URL?
Tom
Powinienem wspomnieć, że jest zakodowany w utf8; svg to format. Podany link zawiera kilka przykładów.
Josh z Qaribou
1
Jak używać obracanego obrazu SVG, używając tego?
Somnath Kharat,
Czy wszyscy nie kochamy IE;) Jak zwykle wymaga to dodatkowej pracy, aby działał na wszystkich przeglądarkach. Przykład przystosowałem do obsługi IE, mam nadzieję, że to pomoże.
Tom
31

Wiem, że ten post jest trochę stary, ale widziałem tak wiele złych informacji na ten temat w SO, że mogłem krzyczeć. Muszę więc po prostu wrzucić moje dwa centy z zupełnie innym podejściem, które wiem, że działa, ponieważ używam go niezawodnie na wielu mapach. Poza tym, uważam, że OP chciał mieć możliwość obracania znacznika strzałki wokół punktu mapy, co różni się od obracania ikony wokół własnej osi x, y, która zmieni miejsce, w którym wskazuje znacznik strzałki na mapie.

Po pierwsze, pamiętaj, że bawimy się mapami Google i SVG, więc musimy dostosować się do sposobu, w jaki Google wdraża implementację SVG dla znaczników (a właściwie symboli). Google ustawia kotwicę dla obrazu znacznika SVG na 0,0, który NIE JEST lewym górnym rogiem SVG viewBox. Aby to obejść, musisz nieco inaczej narysować obraz SVG, aby dać Google to, czego chce ... tak, odpowiedź brzmi w sposobie, w jaki faktycznie tworzysz ścieżkę SVG w swoim edytorze SVG (Illustrator, Inkscape itp.) .).

Pierwszym krokiem jest pozbycie się viewBox. Można to zrobić, ustawiając viewBox w swoim XML na 0 ... to prawda, tylko jedno zero zamiast zwykłych czterech argumentów dla viewBox. Spowoduje to wyłączenie pola widoku (i tak, jest to semantycznie poprawne). Prawdopodobnie zauważysz natychmiastowy skok rozmiaru obrazu, gdy to zrobisz, a dzieje się tak, ponieważ plik SVG nie ma już podstawy (ViewBox) do skalowania obrazu. Dlatego tworzymy to odniesienie bezpośrednio, ustawiając szerokość i wysokość na rzeczywistą liczbę pikseli, które chcesz, aby obraz znajdował się w edytorze XML edytora SVG.

Ustawiając szerokość i wysokość obrazu svg w edytorze XML, tworzysz podstawę skalowania obrazu, a rozmiar ten domyślnie przyjmuje wartość 1 dla właściwości skali markera. Możesz zobaczyć zalety tego dla dynamicznego skalowania znacznika.

Teraz, gdy masz już rozmiar obrazu, przesuwaj go, aż część obrazu, którą chcesz mieć jako kotwica, znajdzie się nad współrzędnymi 0,0 edytora SVG. Po wykonaniu tej czynności skopiuj wartość atrybutu d ścieżki svg. Zauważysz, że około połowa liczb jest ujemna, co jest wynikiem wyrównania punktu zakotwiczenia dla 0,0 obrazu zamiast viewBox.

Użycie tej techniki pozwoli ci wtedy poprawnie obrócić znacznik wokół szer i lng punktu na mapie. To jedyny niezawodny sposób na powiązanie punktu na znaczniku svg, który chcesz, z szerokością i długością miejsca znacznika.

Próbowałem zrobić do tego JSFiddle , ale jest tam jakiś błąd w implementacji, jeden z powodów, dla których nie przepadam za reinterpretacją kodu. Zamiast tego zamieściłem poniżej w pełni samodzielny przykład, który możesz wypróbować, dostosować i wykorzystać jako odniesienie. To ten sam kod, który wypróbowałem w JSFiddle, który się nie powiódł, ale przepływa przez Firebuga bez jęku.

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

Dokładnie to robi Google dla swoich własnych kilku symboli dostępnych w klasie SYMBOL interfejsu API Maps, więc jeśli to Cię nie przekonuje ... W każdym razie mam nadzieję, że pomoże ci to poprawnie stworzyć i skonfigurować znacznik SVG dla Twoje mapy Google starają się.

Olśnienie
źródło
2
Dobra
Rob Schmuecker
„<3” To są podstawowe informacje, które powinny znaleźć się w dokumentacji Google.
user7653815
12

Tak, możesz użyć pliku .svg dla ikony, tak jak możesz .png lub innego formatu pliku obrazu. Po prostu ustaw adres URL ikony na katalog, w którym znajduje się plik .svg. Na przykład:

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
});
ThePersonWithoutC
źródło
1
Obiekt ikony, który pokazujesz, dotyczy standardowego znacznika, a nie markera SVG. Znacznik svg wykorzystuje właściwości klasy symboli, które są następnie przypisywane jako właściwość icon klasy znacznika. (zobacz obiekt ikony MrUpsidown dla poprawnego odniesienia ...)
Epiphany
2
Spowoduje to również uszkodzenie, jeśli plik SVG ma więcej niż jedną ścieżkę „d” (zwykle skojarzoną z więcej niż jedną warstwą obrazu svg).
Objawienie Pańskie
2
Zwróć uwagę, że plik svg powinien wyraźnie ustawić wymiary ikony w następujący sposób: width="33px" height="50px"- patrz stackoverflow.com/a/21783089/165673
Yarin
9

Wszystko idzie lepiej, teraz możesz używać plików SVG.

        marker = new google.maps.Marker({
            position: {lat: 36.720426, lng: -4.412573},
            map: map,
            draggable: true,
            icon: "img/tree.svg"
        });
gengns
źródło
1
nie pozwala na rotację
Matt Westlake,
6

Jak wspominali inni w tym wątku, nie zapomnij jawnie ustawić atrybutów szerokości i wysokości w pliku svg w następujący sposób:

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

jeśli tego nie zrobisz, żadna manipulacja js nie pomoże, ponieważ gmaps nie będzie miał punktu odniesienia i zawsze będzie używał standardowego rozmiaru.

(Wiem, że wspomniano o tym w niektórych komentarzach, ale łatwo je przeoczyć. Te informacje pomogły mi w różnych przypadkach)

Larzan
źródło
1

OK! Zrobiłem to wkrótce w mojej sieci, próbuję na dwa sposoby utworzyć niestandardowy znacznik mapy google, ten kod uruchamiania przy użyciu canvg.js jest najlepszą kompatybilnością z przeglądarką.Komentowany kod nie obsługuje obecnie IE11.

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>

Słońce
źródło
-4

Musisz zdać optimized: false.

Na przykład

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

Bez przechodzenia optimized: false, mój plik SVG pojawił się jako obraz statyczny.

Jeremy Eaton
źródło