Как использовать маркеры SVG в Google Maps API v3

91

Могу ли я использовать преобразованный файл image.svg в качестве значка карты Google. Я преобразовывал свое png-изображение в svg, и я хочу использовать его как символ карты Google, который можно повернуть. Я уже пробовал использовать символ карты Google, но я хочу иметь значок, такой как автомобиль, человек и т.д ... Вот почему я преобразовал свои некоторые файлы png в svg, точно так же, как этот пример сайта, что он использует для этих http: / /www.goprotravelling.com/

Джемз
источник
1
Для тех, кто ищет этот аналогичный вопрос: частичное решение, совместимое с IE 9+, здесь: stackoverflow.com/a/30890373/634386 поместит SVG в DOM, а не на холст, чтобы вы могли манипулировать с помощью CSS3 после (если вы ' Вы хотите повернуть этот элемент на лету).
Майк Корменди,

Ответы:

146

Вы можете визуализировать свой значок, используя обозначение SVG Path .

См. Дополнительную информацию в документации Google .

Вот простой пример:

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

Вот рабочий пример того, как отображать и масштабировать значок SVG маркера:

Демо JSFiddle

Редактировать:

Другой пример со сложной иконкой:

Демо JSFiddle

Изменить 2:

А вот как можно использовать файл SVG в качестве значка:

Демо JSFiddle

MrUpsidown
источник
, очень сложно сделать car svg.
jemz
У вас есть SVG-изображение той машины, которую вы хотите? Затем просто откройте его в текстовом редакторе и найдите в нем путь!
MrUpsidown
3
SVG обычно используется для значков и других символов. Один цвет. Это просто путь, как буква в шрифте. Плюсы в том, что вы можете легко масштабировать, вращать и менять цвет без потери качества. Это векторная фигура.
MrUpsidown
1
Это была одна из самых полезных вещей, которые я прочитал в этом году! Большое спасибо
Джонатан Ла'Фей
2
@MrUpsidown Но, конечно, SVG отлично работает вне карт - там никогда не было проблем. Это связано с ошибкой в ​​поддержке Google SVG в их рендеринге холста, который можно отключить, чтобы вместо этого SVG вставлялись в DOM. Кроме того, существует проблема с вычисленными размерами маркеров, которые в реализации для маркеров карты имеют несколько свойств, которые могут изменять размер. Я нашел здесь частичное решение: stackoverflow.com/a/30890373/634386
Майк Корменди
68

Если вам нужен полный svg, а не только путь, и вы хотите, чтобы он мог быть изменен на стороне клиента (например, изменить текст, скрыть детали, ...), вы можете использовать альтернативный URL-адрес данных с включенным 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 () используется для получения кодировки base64 из текста SVG. Вы также можете использовать http://dopiaza.org/tools/datauri/index.php для создания URL-адресов базовых данных.

Вот полный пример 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>

Дополнительную информацию можно найти здесь .

Избегайте кодировки base64:

Чтобы избежать кодирования base64, вы можете заменить его 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(svg)на'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg)

Это должно работать с современными браузерами до IE9. Преимущество в том, что encodeURIComponentэто функция js по умолчанию, доступная во всех современных браузерах. Вы также можете получить ссылки меньшего размера, но вам нужно протестировать это и подумать об использовании 'вместо "в вашем svg.

Также см. Оптимизация SVG в URI данных для получения дополнительной информации.

Поддержка IE: для поддержки маркеров SVG в IE необходимы две небольших адаптации, как описано здесь: Маркеры SVG в IE . Я обновил пример кода для поддержки IE.

Том
источник
3
Хорошая информация, но заметьте, что кодировка base64 на самом деле не нужна или нежелательна. Вместо этого вы можете использовать кодировку svg непосредственно в URI данных, например data:image/svg+xml;utf8,. Дополнительная информация: css-tricks.com/probably-dont-base64-svg
Джош из Карибу
Вы правы, было бы замечательно, если бы можно было избежать кодировки base64. Как вы это сделали, могли бы вы привести пример? Если я просто добавлю код svg в URI, он не будет работать с некоторыми символами, например #, вы использовали кодировку URL?
Tom
Я должен упомянуть, что он закодирован в utf8; svg - это формат. По предоставленной ссылке есть несколько примеров.
Джош из Карибу,
1
Как использовать поворот изображения SVG с помощью этого?
Сомнатх Харат
Разве мы не все любим IE;) Как обычно, требуется дополнительная работа, чтобы заставить его работать во всех браузерах. Я адаптировал пример для поддержки IE, надеюсь, это поможет.
Tom
31

Я знаю, что этот пост немного устарел, но я видел так много плохой информации по этому поводу в SO, что я мог кричать. Так что я просто должен вложить свои два цента в совершенно другой подход, который, как я знаю, работает, поскольку я надежно использую его на многих картах. Кроме того, я считаю, что OP также хотел иметь возможность вращать маркер стрелки вокруг точки карты, что отличается от поворота значка вокруг собственной оси x, y, которая изменит положение маркера стрелки на карте.

Во-первых, помните, что мы играем с картами Google и SVG, поэтому мы должны приспособить способ, которым Google развертывает свою реализацию SVG для маркеров (или фактически символов). Google устанавливает привязку для изображения маркера SVG на 0,0, который НЕ ЯВЛЯЕТСЯ верхним левым углом окна просмотра SVG. Чтобы обойти это, вы должны нарисовать свое SVG-изображение немного по-другому, чтобы дать Google то, что он хочет ... да, ответ в том, как вы фактически создаете путь SVG в своем редакторе SVG (Illustrator, Inkscape и т. Д. .).

Первый шаг - избавиться от viewBox. Это можно сделать, установив для viewBox в вашем XML значение 0 ... правильно, всего один ноль вместо обычных четырех аргументов для viewBox. Это отключает окно просмотра (и да, это семантически правильно). Вы, вероятно, сразу заметите скачок размера вашего изображения, когда вы это сделаете, и это потому, что у svg больше нет основы (viewBox) для масштабирования изображения. Таким образом, мы создаем эту ссылку напрямую, устанавливая ширину и высоту в соответствии с фактическим количеством пикселей, которое вы хотите, чтобы ваше изображение было в редакторе XML вашего редактора SVG.

Устанавливая ширину и высоту изображения svg в редакторе XML, вы создаете базовую линию для масштабирования изображения, и этот размер по умолчанию становится значением 1 для свойств масштаба маркера. Вы можете видеть преимущества этого для динамического масштабирования маркера.

Теперь, когда у вас есть размер вашего изображения, переместите изображение до тех пор, пока часть изображения, которую вы хотите иметь в качестве привязки, не окажется над координатами 0,0 редактора svg. Как только вы это сделаете, скопируйте значение атрибута d пути svg. Вы заметите, что около половины чисел отрицательны, что является результатом выравнивания точки привязки для 0,0 изображения вместо viewBox.

Использование этой техники позволит вам правильно повернуть маркер вокруг точки широты и долготы на карте. Это единственный надежный способ привязать точку на маркере SVG, которую вы хотите, к широте и долготе местоположения маркера.

Я попытался создать для этого JSFiddle , но в его реализации есть некоторая ошибка, одна из причин, по которой я не очень люблю переинтерпретированный код. Поэтому вместо этого я включил ниже полностью автономный пример, который вы можете попробовать, адаптировать и использовать в качестве справочника. Это тот же код, который я пробовал в JSFiddle, но он не удался, но он проходит через Firebug без единого хныканья.

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

Это именно то, что Google делает для нескольких собственных символов, доступных в классе SYMBOL API Карт, поэтому, если это вас не убедит ... В любом случае, я надеюсь, что это поможет вам правильно создать и настроить маркер SVG для ваши карты Google endevours.

Богоявление
источник
2
Хороший ответ, я сделал рабочую скрипку вашего кода, чтобы люди увидели jsfiddle.net/v2pjfp7r
Роб Шмуекер,
"<3" Это важная информация, которая должна быть частью документации Google.
user7653815
12

Да, вы можете использовать файл .svg для значка так же, как вы можете .png или другой формат файла изображения. Просто установите URL-адрес значка в каталог, в котором находится файл .svg. Например:

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
источник
1
Отображаемый объект значка предназначен для стандартного маркера, а не для маркера SVG. Маркер svg использует свойства класса символа, которые затем назначаются как свойство значка класса маркера. (см. объект значка MrUpsidown для правильной ссылки ...)
Epiphany
2
Это также сломается, если SVG имеет более одного пути 'd' (обычно связанный с более чем одним слоем в изображении svg).
Богоявление,
2
Обратите внимание, что ваш файл svg должен явно устанавливать размеры значка следующим образом: width="33px" height="50px"- см. Stackoverflow.com/a/21783089/165673
Yarin
9

Дела идут лучше, сейчас вы можете использовать файлы SVG.

        marker = new google.maps.Marker({
            position: {lat: 36.720426, lng: -4.412573},
            map: map,
            draggable: true,
            icon: "img/tree.svg"
        });
Gengns
источник
1
не допускает ротации
Мэтт Вестлейк
6

Как упоминалось другими в этом потоке, не забудьте явно установить атрибуты ширины и высоты в svg следующим образом:

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

Если вы этого не сделаете, никакие js-манипуляции вам не помогут, поскольку gmaps не будут иметь системы отсчета и всегда будут использовать стандартный размер.

(я знаю, что об этом упоминалось в некоторых комментариях, но их легко пропустить. Эта информация помогла мне в разных случаях)

Ларзан
источник
1

ОК! Вскоре я сделал это в своей сети. Я пробую два способа создать пользовательский маркер карты Google. Использование этого кода запуска canvg.js - лучшая совместимость для браузера. Закомментированный код не поддерживает 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>

солнце
источник
-4

Вам нужно пройти optimized: false.

Например

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

Не проходя мимо optimized: false, мой svg выглядел как статичное изображение.

Джереми Итон
источник