【问题标题】:How to use SVG markers in Google Maps API v3如何在 Google Maps API v3 中使用 SVG 标记
【发布时间】:2014-08-16 07:36:54
【问题描述】:

我可以将转换后的 image.svg 用作谷歌地图图标吗?我正在将我的 png 图像转换为 svg,我想使用这个可以旋转的谷歌地图符号。我已经尝试使用谷歌地图符号,但我想要一个像汽车、人等的图标......这就是为什么我将我的一些 png 文件转换为 svg,就像这个示例网站一样,他对这些使用了什么http://www.goprotravelling.com/

【问题讨论】:

  • 对于那些搜索类似问题的人:此处提供部分 IE 9+ 兼容解决方案:stackoverflow.com/a/30890373/634386 将在 DOM 中而不是在画布上放置 SVG,以便您可以在之后使用 CSS3 进行操作(如果您正在寻找专门动态旋转该元素)。

标签: google-maps google-maps-api-3 svg


【解决方案1】:

您可以使用SVG Path notation 呈现您的图标。

更多信息请参见Google documentation。

这是一个基本的例子:

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 demo

编辑:

这里还有一个复杂图标的例子:

JSFiddle demo

编辑 2:

以下是如何将 SVG 文件作为图标:

JSFiddle demo

【讨论】:

  • ,制作汽车svg非常困难。
  • 你有你想要的那辆车的 SVG 图像吗?然后用文本编辑器打开它,在里面找到路径!
  • SVG 通常用于图标和其他符号。一种颜色。它只是一条路径,就像字体中的一个字母。优点是您可以轻松地对其进行缩放、旋转和更改颜色,而不会损失质量。这是一个矢量形状。
  • 这是我今年读到的最有用的东西之一!非常感谢
  • @MrUpsidown 但是 SVG 在地图之外当然可以正常工作 - 从来没有出现过问题。这与 Google 在其画布渲染中对 SVG 的支持存在故障有关 - 可以将其关闭,以便将 SVG 插入到 DOM 中。然后是标记的计算大小的问题,在地图标记的实现中有几个属性可以强制大小。我在这里找到了部分解决方案:stackoverflow.com/a/30890373/634386
【解决方案2】:

是的,您可以使用 .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
});

【讨论】:

  • 您显示的图标对象用于标准标记,而不是 SVG 标记。 svg 标记使用符号类的属性,然后将其指定为标记类的图标属性。 (请参阅 MrUpsidown 图标对象以获取正确的参考...)
  • 如果 SVG 有多个“d”路径(通常与 svg 图像中的多个图层相关联),这也会中断。
  • 请注意,您的 svg 文件应明确设置图标的尺寸,如下所示:width="33px" height="50px" - 请参阅 stackoverflow.com/a/21783089/165673
【解决方案3】:

我知道这篇文章有点老了,但我在 SO 上看到了太多关于这方面的糟糕信息,以至于我大喊大叫。所以我只需要用我知道可行的完全不同的方法投入我的两分钱,因为我在许多地图上都可靠地使用它。除此之外,我相信 OP 还希望能够围绕地图点旋转箭头标记,这与围绕它自己的 x、y 轴旋转图标不同,这将改变箭头标记在地图上指向的位置。

首先,请记住我们正在使用 Google 地图和 SVG,因此我们必须适应 Google 为标记(或实际上是符号)部署其 SVG 实现的方式。 Google 将 SVG 标记图像的锚点设置为 0,0,这不是 SVG 视图框的左上角。为了解决这个问题,您必须以不同的方式绘制您的 SVG 图像,以便为 Google 提供所需的内容……是的,答案在于您在 SVG 编辑器(Illustrator、Inkscape 等)中实际创建 SVG 路径的方式。 .).

第一步,是去掉viewBox。这可以通过将 XML 中的 viewBox 设置为 0 来完成……没错,只是一个 0,而不是 viewBox 通常的四个参数。这会关闭视图框(是的,这在语义上是正确的)。执行此操作时,您可能会立即注意到图像的大小跳跃,这是因为 svg 不再具有缩放图像的基础(视图框)。因此,我们通过将宽度和高度设置为您希望图像在 SVG 编辑器的 XML 编辑器中的实际像素数来直接创建该引用。

通过在 XML 编辑器中设置 svg 图像的宽度和高度,您可以创建用于缩放图像的基线,并且默认情况下,该大小变为标记缩放属性的值 1。您可以看到这对标记的动态缩放的优势。

现在您已经确定了图像大小,移动图像直到您希望作为锚点的图像部分位于 svg 编辑器的 0,0 坐标之上。完成此操作后,复制 svg 路径的 d 属性的值。您会注意到大约一半的数字是负数,这是将锚点对准图像的 0,0 而不是 viewBox 的结果。

然后,使用此技术可以让您围绕地图上的 lat 和 lng 点正确旋转标记。这是将 svg 标记上的点绑定到标记位置的纬度和经度的唯一可靠方法。

我尝试创建a JSFiddle for this,但其中的实现存在一些错误,这是我不太喜欢重新解释代码的原因之一。因此,我在下面提供了一个完全独立的示例,您可以尝试、调整和用作参考。这与我在 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 所做的,因为它在 Maps API 的 SYMBOL 类中提供了一些可用的符号,所以如果这不能说服您... 无论如何,我希望这将帮助您正确地为您的 Google 地图制作和设置 SVG 标记。

【讨论】:

  • 不错的答案,我已经为您的代码做了一个工作小提琴,供人们查看jsfiddle.net/v2pjfp7r
  • "
  • 这是我需要的信息!如果您在 Illustrator 中创建 SVG(在遵循上述关于 viewBox 的建议之后),请确保使用“另存为...”,然后将其另存为 SVG,“导出屏幕...”将不起作用。
  • 这是一个完美的答案 - 帮助我解决了标记在缩放时漂移的问题。原来是锚点没有设置在正确的坐标系中造成的。
【解决方案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 显示为静态图像。

【讨论】:

    【解决方案5】:

    如果您不仅需要完整的 svg 路径,而且还希望它可以在客户端进行修改(例如更改文本、隐藏详细信息等),您可以使用包含 svg 的替代数据“URL”:

    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() 用于从 SVG 文本中获取 base64 编码。您也可以使用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>
    

    更多信息可以在here找到。

    避免 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 中使用 ' 而不是 "。

    另请参阅Optimizing SVGs in data URIs 了解更多信息。

    IE 支持: 为了在 IE 中支持 SVG 标记,需要进行两个小的修改,如下所述:SVG Markers in IE。我更新了示例代码以支持 IE。

    【讨论】:

    • 好信息,但请注意,base64 编码实际上并不是必需的或可取的。您可以直接在数据 URI 中使用 svg 编码,例如 data:image/svg+xml;utf8,。更多信息:css-tricks.com/probably-dont-base64-svg
    • 你说得对,如果我们能避免使用 base64 编码,那就太好了。你是怎么做到的,能举个例子吗?如果我只是将 svg 代码添加到 URI,它不适用于 # 之类的某些字符,您是否使用了 URL 编码?
    • 我应该提到它是 utf8 编码的; svg 是格式。提供的链接有几个示例。
    • 如何使用这个来旋转svg图片?
    • 谷歌地图团队对街景、放大、缩小、全屏等默认图标使用相同的方法。
    【解决方案6】:

    情况正在好转,现在您可以使用 SVG 文件了。

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

    【讨论】:

    • 不允许旋转
    【解决方案7】:

    好的!我很快在我的网络上完成了这个,我尝试了两种方法来创建自定义谷歌地图标记,这个运行代码使用 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>

    【讨论】:

      【解决方案8】:

      正如本帖中其他人所提到的,不要忘记像这样在 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 操作都无法帮助您,因为 gmap 将没有参考框架,并且始终使用标准尺寸。

      (我知道在某些 cmets 中已经提到过,但很容易错过。这些信息在各种情况下都对我有所帮助)

      【讨论】:

        猜你喜欢
        • 2013-04-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-19
        • 2012-01-25
        • 2012-05-11
        • 2011-09-05
        • 2016-11-06
        相关资源
        最近更新 更多