【问题标题】:How to access Google Maps API v3 marker's DIV and its pixel position?如何访问 Google Maps API v3 标记的 DIV 及其像素位置?
【发布时间】:2011-02-10 02:10:07
【问题描述】:

代替 Google Maps API 的默认信息窗口,我将在标记上使用其他 jQuery 工具提示插件。所以我需要获取标记的 DIV 及其像素位置。

但无法获取它,因为某些标记没有 id 或类。只有我可以从标记对象和未记录的 pixelBounds 对象访问地图画布 div。

  1. 如何访问标记的 DIV?
  2. 在哪里可以获得 DIV 的像素位置?我可以将 lat-lng 位置转换为像素值吗?

== 附:

我也尝试了下面的代码,但是当我滚动地图时它并没有改变。

var marker = new google.maps.Marker({...});
google.maps.event.addListener(marker, 'click', function() {
    var px = this.getMap().getProjection().fromLatLngToPoint(this.getPosition());
    console.log("(" + px.x + "," + px.y + ")");
});

【问题讨论】:

  • 这个问题不应该被标记为接受吗?您的问题似乎已得到解决。
  • @jeff -- 您正在编辑超过 2 年的问题,不断地将它们推到活动列表的顶部。代码已经正确格式化,使颜色漂亮是一个小改动,没有必要。
  • @LittleBobbyTables - 这个问题已经被浏览了将近 19,000 次。我想有人最终会发现语法高亮很有用。

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


【解决方案1】:

试试这个方法,按事件得到 div。

marker.addListener("click", markerClicked);

function markerClicked(event) {
    // here you can get the marker div by event.currentTarget
}

【讨论】:

    【解决方案2】:

    在许多情况下,使用复杂数学计算并更改已接受答案中的大头针位置可能是合适的。

    对于我的特殊用途,我刚刚创建了一个透明的 PNG,其画布比我需要的图标大得多。然后我只是尝试在透明背景中移动图钉并将新图像应用到地图上。

    以下是添加自定义图钉图像的规范,并附有示例: https://developers.google.com/maps/documentation/javascript/examples/icon-simple

    即使您放大,此方法也肯定会缩放为像素偏移量,而不是实际不同的经度/纬度。

    【讨论】:

      【解决方案3】:

      我发现分配自定义图标并使用 img src 属性来获取元素是最简单的。您仍然可以使用默认的谷歌地图图标,只需将其保存在本地即可。

      $("#map img[src='my_marker.png']").getBoundingClientRect();
      

      【讨论】:

        【解决方案4】:

        任何仍在寻找答案的人,请看这里:http://code.google.com/p/google-maps-utility-library-v3/wiki/Libraries 在其他一些有用的谷歌地图东西中,有 RichMarker,它允许您添加您选择的 DOM 元素作为可拖动标记。只需添加 class/id 以使用 jQuery 处理。

        【讨论】:

          【解决方案5】:

          使用 MBO 的代码时要记住的一件事: 当地图瓦片重复时,map.getBounds().getSouthWest() 会返回“-180”,与地图的位置无关。我在这种情况下使用的后备方法是计算到中心而不是左上角的像素距离,因为map.getCenter() 在任何情况下似乎都会返回当前居中的点。例如。 (使用 jQuery):

          // Calculate marker position in pixels form upper left corner
          var pixelCoordsCenter = map.getProjection().fromLatLngToPoint(map.getCenter());
          pixelOffset = new google.maps.Point(
              Math.floor((pixelCoordsMarker.x - pixelCoordsCenter.x) * scale + $(container).width()/2),
              Math.floor((pixelCoordsMarker.y - pixelCoordsCenter.y) * scale + $(container).height()/2)
          );
          

          【讨论】:

          • 这应该接近顶部,对于国际风格的地图来说是一个极其重要的特征。这个 sn-p 最终纠正了我所有的定位问题。
          【解决方案6】:
          var overlay = new google.maps.OverlayView();
          overlay.draw = function() {};
          overlay.setMap(map);
          
          var proj = overlay.getProjection();
          var pos = marker.getPosition();
          var p = proj.fromLatLngToContainerPixel(pos);
          

          您现在可以通过 p.x 和 p.y 访问您的像素坐标。

          以下添加的帖子评论:

          叠加投影的缺点是,在您的地图画布完成加载之前,它不会被初始化。我有以下监听器,它将在地图完成加载时强制我需要触发的任何方法。

          google.maps.event.addListener(map, 'idle', functionName());
          

          与此同时,我使用以下检查以避免在绘制之前出现任何错误。

          if(overlay.getProjection()) {
            // code here
          }
          

          【讨论】:

          • 如果这能奏效,那就太棒了。 overlay.getProjection() 返回undefined
          • overlay.getProjection 仅在地图加载后才被初始化

            为了规避这一点并对其进行初始化,我有一个监听器来调用使用它的函数。我会将代码添加到我的评论中。
          • 非常感谢您为我更新此内容!我已经使用了事件监听器,所以我会尽快实现它!
          【解决方案7】:

          准备复制/粘贴的工作 sn-p jQuery 样式:

          第 1 步 - 初始化您的地图和选项

          <html>
          <head>
          <script src="get-your-jQuery" type="text/javascript"></script>
          <script src="get-your-maps.API" type="text/javascript"></script>
          <script type="text/javascript">
          <!--
          $(document).ready(function(){
          var bucharest = new google.maps.LatLng(44.43552, 26.10250);
          var options = {
          zoom: 14,
          center: bucharest,
          mapTypeId: google.maps.MapTypeId.ROADMAP 
          }
          

          如你所见,lower,变量 map 前面没有 VAR,因为它应该是 Global,因为我们使用另一个函数来获取 fromLatLngToContainerPixel。更多详情请查看closures

          map = new google.maps.map($("#map_canvas")[0], options);
          
          var marker = new google.maps.Marker({
          position: google.maps.LatLng(44.4407,26.0864),
          map: map
          });
          
          new google.maps.event.addListener(marker, 'mouseover', function(){
                    placeMarker( marker.getPosition(),'#tooltip');//param1: latlng, param2: container to place result
          });
          
          new google.maps.event.addListener(map, 'bounds_changed', function(){
                  $("#tooltip").css({display:'none'}); //this is just so you can see that all goes well ;)
              });
          
           overlay = new google.maps.OverlayView();
           overlay.draw = function() {};
           overlay.setMap(map);
          
          }); //here ends jQuery.ready
          
          function placeMarker(location, ID){
          var containerPixel = overlay.getProjection().fromLatLngToContainerPixel(location);
          var divPixel       = overlay.getProjection().fromLatLngToDivPixel(location);
          $(ID).css({top:containerPixel.y, left:containerPixel.x, 'dislay':'block'});
          }
          //--> 
          </script>
          </head>
          <body>
          <div id="tooltip" style="width:100px; height:100px; position:absolute; z-index:1; background:#fff">Here I am!</div>
          <div id="map_canvas" style="width:300px; height:300px"></div>
          </body>
          </html>
          

          【讨论】:

            【解决方案8】:

            好吧,如果您必须访问 DIV,这里有一些代码。请注意,这仅适用于标准标记 (20x34px),它会找到所有标记。您可能希望改进此 hack 以满足您的需求...

            当心!这是一个黑客

            var a=document.getElementById('map_canvas');
            var b=a.getElementsByTagName('img');
            var i, j=b.length;
            for (i=0; i<j; i++) {
              if(b[i].src.match('marker_sprite.png')){
                if(b[i].style.width=='20px' && b[i].style.height=='34px') {
                  c=b[i].parentElement;
                  console.log(c.style.top+":"+c.style.left);
                  // this is a marker's enclosing div
            
                }
              }
            }
            

            【讨论】:

              【解决方案9】:

              MapCanvasProjection 的fromLatLngToContainerPixel() 可能是作者所追求的。它将为您提供相对于地图容器的像素偏移量。我做了一些实验,找到了“最简单”的工作解决方案。 (我希望 Google 让这个功能更易于使用!)

              首先你声明一个OverlayView 的子类,像这样:

              function CanvasProjectionOverlay() {}
              CanvasProjectionOverlay.prototype = new google.maps.OverlayView();
              CanvasProjectionOverlay.prototype.constructor = CanvasProjectionOverlay;
              CanvasProjectionOverlay.prototype.onAdd = function(){};
              CanvasProjectionOverlay.prototype.draw = function(){};
              CanvasProjectionOverlay.prototype.onRemove = function(){};
              

              然后在其他地方在你的代码中实例化地图,你也实例化这个 OverlayView 并设置它的地图,像这样:

              var map = new google.maps.Map(document.getElementById('google-map'), mapOptions);
              
              // Add canvas projection overlay so we can use the LatLng to pixel converter
              var canvasProjectionOverlay = new CanvasProjectionOverlay();
              canvasProjectionOverlay.setMap(map);
              

              然后,当您需要使用fromLatLngToContainerPixel 时,您只需这样做:

              canvasProjectionOverlay.getProjection().fromLatLngToContainerPixel(myLatLng);
              

              请注意,因为 MapCanvasProjection 对象只有在调用 draw() 时才可用,这是在地图的 idle 之前的某个时间,我建议创建一个布尔“mapInitialized”标志,在第一个地图 @987654329 上将其设置为 true @ 打回来。然后再做你需要做的事情。

              【讨论】:

                【解决方案10】:

                Rene 的回答只为您提供“世界坐标”(即独立于缩放级别和视口的坐标)。不过,MBO 的答案似乎是正确的,因此您应该接受并投票(我不能,因为我刚刚注册过),否则该解决方案可能很容易被忽略。

                至于“更简单”的版本,您可以改用 MapCanvasProjection 中的方法,但这意味着您必须自己制作叠加层。有关示例,请参阅here。 :P

                【讨论】:

                  【解决方案11】:

                  我真的不明白为什么要为标记获取特定的 div?如果你想显示工具提示,那么你只需要标记锚的像素位置(以及关于标记大小和锚位置的知识),而不是 div 元素。当 google.maps 端发生事件时,您始终可以手动触发打开和关闭工具提示。

                  要获取给定标记的锚点的像素位置,您可以使用以下代码:

                  var scale = Math.pow(2, map.getZoom());
                  var nw = new google.maps.LatLng(
                      map.getBounds().getNorthEast().lat(),
                      map.getBounds().getSouthWest().lng()
                  );
                  var worldCoordinateNW = map.getProjection().fromLatLngToPoint(nw);
                  var worldCoordinate = map.getProjection().fromLatLngToPoint(marker.getPosition());
                  var pixelOffset = new google.maps.Point(
                      Math.floor((worldCoordinate.x - worldCoordinateNW.x) * scale),
                      Math.floor((worldCoordinate.y - worldCoordinateNW.y) * scale)
                  );
                  

                  pixelDistance 中,您可以获得从地图左上角计算的特定标记锚点的偏移量(您可以从map.getDiv() div 中获取它的位置)。为什么它会这样工作(或者有更好的方法吗?)您可以阅读documentation of google maps overlays

                  【讨论】:

                  • 除了工具提示,我想用 jQuery 为标记设置动画,这就是为什么我需要访问标记的 DIV。现在我知道我无法通过地图 API v3 访问它,需要使用 OverlayView 重新实现标记类。 :(
                  • 有没有人有好的反向功能?
                  • @AnkitAggarwal 不幸的是,我目前的工作不涉及使用 Google 地图。这个答案正是我在某个项目中必须自己开发的,但除此之外我对地图没有太多经验。
                  • 同样的事情,但更详细,并以here为例。
                  • @dukedave:你只需像这样jQuery('#map').css('top') 得到#maptop 并加起来fromLatLngToPoint 函数。 (worldPoint.y - topRight.y) becomes (worldPoint.y - topRight.y + jQuery('#map').css('top'))。这个没有测试!但你明白了。
                  猜你喜欢
                  • 2012-01-04
                  • 2016-11-06
                  • 1970-01-01
                  • 2012-01-28
                  • 2012-01-06
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多