Cara menggunakan penanda SVG di Google Maps API v3

91

Dapatkah saya menggunakan image.svg saya yang telah dikonversi sebagai ikon peta google. Saya mengubah gambar png saya menjadi svg dan saya ingin menggunakan simbol peta google seperti ini yang dapat diputar. Saya sudah mencoba menggunakan simbol google map tetapi saya ingin memiliki ikon seperti car, man, dll ... Itulah mengapa saya mengonversi beberapa file png saya ke svg, seperti situs contoh ini apa yang dia gunakan untuk http: / /www.goprotravelling.com/

jemz
sumber
1
Bagi mereka yang mencari pertanyaan serupa ini: solusi yang kompatibel dengan IE 9+ di sini: stackoverflow.com/a/30890373/634386 akan menempatkan SVG di DOM alih-alih di kanvas sehingga Anda dapat memanipulasi dengan CSS3 setelahnya (jika Anda ' sedang mencari untuk memutar elemen itu secara khusus dengan cepat).
Mike Kormendy

Jawaban:

146

Anda dapat membuat ikon Anda menggunakan notasi Jalur SVG .

Lihat dokumentasi Google untuk informasi lebih lanjut.

Berikut adalah contoh dasarnya:

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

Berikut adalah contoh kerja tentang cara menampilkan dan menskalakan ikon SVG marker:

Demo JSFiddle

Edit:

Contoh lain di sini dengan ikon kompleks:

Demo JSFiddle

Edit 2:

Dan inilah cara Anda memiliki file SVG sebagai ikon:

Demo JSFiddle

MrUpsidown
sumber
, sangat sulit membuat mobil svg.
jemz
Apakah Anda memiliki gambar SVG dari mobil yang Anda inginkan? Kemudian buka saja dengan editor teks dan temukan jalur di dalamnya!
MrUpsidown
3
SVG biasanya digunakan untuk ikon dan simbol lainnya. Satu warna. Itu hanya sebuah jalan, seperti sebuah huruf dalam sebuah font. Keuntungannya adalah Anda dapat dengan mudah menskalakannya, memutarnya, dan mengubah warnanya, tanpa kehilangan kualitas. Ini adalah bentuk vektor.
MrUpsidown
1
Itu adalah salah satu hal paling berguna yang saya baca tahun ini! Terima kasih banyak
Jonathan La'Fey
2
@MrUpsidown Tapi tentu saja SVG bekerja dengan baik di luar peta - tidak pernah ada masalah di sana. Ini ada hubungannya dengan kesalahan dalam dukungan Google untuk SVG dalam rendering kanvas mereka - yang dapat dimatikan sehingga SVG dimasukkan ke dalam DOM sebagai gantinya. Lalu ada masalah dengan ukuran penanda yang dihitung, yaitu ada beberapa properti dalam penerapan penanda peta yang dapat memaksa ukuran. Saya telah menemukan solusi parsial di sini: stackoverflow.com/a/30890373/634386
Mike Kormendy
68

Jika Anda memerlukan svg penuh tidak hanya jalur dan Anda ingin itu dapat dimodifikasi di sisi klien (misalnya mengubah teks, menyembunyikan detail, ...) Anda dapat menggunakan data alternatif 'URL' dengan menyertakan 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 () digunakan untuk mendapatkan pengkodean base64 dari teks SVG. Anda juga dapat menggunakan http://dopiaza.org/tools/datauri/index.php untuk membuat URL data dasar.

Berikut adalah contoh lengkap 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>

Informasi tambahan dapat ditemukan di sini .

Hindari pengkodean base64:

Untuk menghindari pengkodean base64, Anda dapat mengganti 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(svg)dengan'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg)

Ini harus bekerja dengan browser modern hingga IE9. Keuntungannya adalah encodeURIComponentfungsi js default dan tersedia di semua browser modern. Anda mungkin juga mendapatkan tautan yang lebih kecil tetapi Anda perlu menguji ini dan mempertimbangkan untuk menggunakan 'alih-alih "di svg.

Lihat juga Mengoptimalkan SVG di URI data untuk info tambahan.

Dukungan IE: Untuk mendukung Penanda SVG di IE, kita memerlukan dua adaptasi kecil seperti yang dijelaskan di sini: Penanda SVG di IE . Saya memperbarui kode contoh untuk mendukung IE.

Tom
sumber
3
Info bagus, tetapi perhatikan singkat bahwa pengkodean base64 sebenarnya tidak diperlukan atau diinginkan. Sebagai gantinya, Anda dapat menggunakan pengkodean svg langsung di URI data, seperti data:image/svg+xml;utf8,. Info lebih lanjut: css-tricks.com/probably-dont-base64-svg
Josh dari Qaribou
Anda benar, alangkah baiknya jika kami dapat menghindari pengkodean base64. Bagaimana Anda melakukannya, bisakah Anda memberikan contoh? Jika saya hanya menambahkan kode svg ke URI itu tidak berfungsi dengan beberapa karakter seperti #apakah Anda menggunakan pengkodean URL?
Tom
Saya harus menyebutkan itu dikodekan utf8; svg adalah formatnya. Tautan yang diberikan memiliki beberapa contoh.
Josh dari Qaribou
1
Bagaimana cara menggunakan gambar rotate svg dengan menggunakan ini?
Somnath Kharat
Bukankah kita semua menyukai IE;) Seperti biasa, ini membutuhkan beberapa pekerjaan tambahan untuk membuatnya berfungsi di semua browser. Saya mengadaptasi contoh untuk mendukung IE, semoga ini membantu.
Tom
31

Saya tahu posting ini agak tua, tetapi saya telah melihat begitu banyak informasi buruk tentang ini di SO sehingga saya bisa berteriak. Jadi saya hanya perlu mengeluarkan dua sen saya dengan pendekatan berbeda yang saya tahu berhasil, karena saya menggunakannya dengan andal di banyak peta. Selain itu, saya yakin OP menginginkan kemampuan untuk memutar penanda panah di sekitar titik peta juga, yang berbeda dengan memutar ikon di sekitar sumbu x, y miliknya sendiri yang akan mengubah tempat yang ditunjuk oleh penanda panah pada peta.

Pertama, ingat kita bermain dengan peta Google dan SVG, jadi kita harus mengakomodasi cara Google menyebarkan penerapan SVG untuk penanda (atau sebenarnya simbol). Google menetapkan jangkarnya untuk gambar penanda SVG di 0,0 yang BUKAN di sudut kiri atas kotak tampilan SVG. Untuk menyiasati ini, Anda harus menggambar gambar SVG Anda sedikit berbeda untuk memberikan Google apa yang diinginkannya ... ya jawabannya adalah cara Anda membuat jalur SVG di editor SVG Anda (Illustrator, Inkscape, dll. .).

Langkah pertama, adalah menyingkirkan viewBox. Ini bisa dilakukan dengan menyetel viewBox di XML Anda ke 0 ... itu benar, hanya satu nol daripada empat argumen biasa untuk viewBox. Ini mematikan kotak tampilan (dan ya, ini benar secara semantik). Anda mungkin akan melihat ukuran gambar Anda melonjak dengan cepat ketika Anda melakukan ini, dan itu karena svg tidak lagi memiliki basis (kotak tampilan) untuk menskalakan gambar. Jadi kami membuat referensi itu secara langsung, dengan menyetel lebar dan tinggi ke jumlah piksel sebenarnya yang Anda inginkan untuk gambar Anda ada di editor XML editor SVG Anda.

Dengan mengatur lebar dan tinggi gambar svg di editor XML Anda membuat garis dasar untuk penskalaan gambar, dan ukuran ini menjadi nilai 1 untuk properti skala penanda secara default. Anda dapat melihat keuntungan yang dimilikinya untuk penskalaan dinamis marker.

Sekarang Anda memiliki ukuran gambar Anda, pindahkan gambar sampai bagian gambar yang ingin Anda miliki sebagai jangkar berada di atas koordinat 0,0 dari editor svg. Setelah Anda melakukan ini salin nilai atribut d dari jalur svg. Anda akan melihat sekitar setengah dari angka-angka itu negatif, yang merupakan hasil dari menyelaraskan titik jangkar Anda untuk 0,0 gambar, bukan kotak tampilan.

Menggunakan teknik ini akan memungkinkan Anda memutar penanda dengan benar, di sekitar titik lintang dan ujung pada peta. Ini adalah satu-satunya cara yang dapat diandalkan untuk mengikat titik pada penanda svg yang Anda inginkan ke lintang dan bujur dari lokasi penanda.

Saya mencoba membuat JSFiddle untuk ini , tetapi ada beberapa bug dalam penerapannya, salah satu alasan saya tidak begitu menyukai kode yang ditafsirkan ulang. Jadi sebagai gantinya, saya telah menyertakan contoh lengkap di bawah ini yang dapat Anda coba, adaptasi, dan gunakan sebagai referensi. Ini adalah kode yang sama yang saya coba di JSFiddle yang gagal, namun kode ini melewati Firebug tanpa rengekan.

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

Ini persis seperti yang dilakukan Google untuk beberapa simbolnya sendiri yang tersedia di kelas SYMBOL dari Maps API, jadi jika itu tidak meyakinkan Anda ... Bagaimanapun, saya harap ini akan membantu Anda membuat dan menyiapkan penanda SVG dengan benar untuk peta Google Anda bertahan lama.

Epiphany
sumber
2
Jawaban bagus, saya telah membuat biola yang berfungsi dari kode Anda agar orang dapat melihat jsfiddle.net/v2pjfp7r
Rob Schmuecker
"<3" Ini adalah info penting yang harus menjadi bagian dari dokumentasi google.
pengguna7653815
12

Ya, Anda dapat menggunakan file .svg untuk ikon seperti Anda dapat .png atau format file gambar lainnya. Cukup atur url ikon ke direktori tempat file .svg berada. Sebagai contoh:

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
sumber
1
Objek ikon yang Anda tunjukkan adalah untuk penanda standar, bukan penanda SVG. Penanda svg menggunakan properti kelas simbol, yang kemudian ditetapkan sebagai properti ikon kelas penanda. (Lihat objek ikon MrUpsidown untuk referensi yang benar ...)
Epiphany
2
Ini juga akan rusak jika SVG memiliki lebih dari satu jalur 'd' (biasanya dikaitkan dengan lebih dari satu lapisan pada gambar svg).
Epiphany
2
Perhatikan bahwa file svg Anda harus secara eksplisit mengatur dimensi ikon seperti ini: width="33px" height="50px"- lihat stackoverflow.com/a/21783089/165673
Yarin
9

Semuanya berjalan lebih baik, sekarang Anda dapat menggunakan file SVG.

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

Seperti yang disebutkan oleh orang lain di utas ini, jangan lupa untuk secara eksplisit mengatur atribut lebar dan tinggi di svg seperti ini:

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

jika Anda tidak melakukannya, tidak ada manipulasi js yang dapat membantu Anda karena gmaps tidak akan memiliki kerangka acuan dan selalu menggunakan ukuran standar.

(Saya tahu ini telah disebutkan dalam beberapa komentar, tetapi mudah terlewat. Informasi ini membantu saya dalam berbagai kasus)

Larzan
sumber
1

BAIK! Saya melakukan ini segera di web saya, saya mencoba dua cara untuk membuat penanda peta google kustom, kode run ini menggunakan canvg.js adalah kompatibilitas terbaik untuk browser. Kode Komentar-Keluar tidak mendukung IE11 saat ini.

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>

Matahari
sumber
-4

Anda harus lulus optimized: false.

Misalnya

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

Tanpa lewat optimized: false, svg saya muncul sebagai gambar statis.

Jeremy Eaton
sumber