如何在Google Maps API V3中调用fromLatLngToDivPixel函数?

36

我知道这个方法的存在并已有相关文档,但我不知道如何获取MapCanvasProjection对象。

5个回答

37

请查看http://qfox.nl/notes/116

var overlay = new google.maps.OverlayView();
overlay.draw = function() {};
overlay.setMap(map);
var point = overlay.getProjection().fromLatLngToDivPixel(latLng); 

确实很丑。在v2中更容易-这是google api v3的另一个缺陷!


1
这对我最初来说完美地运作,但如果我平移地图,像素位置就不会更新。但是如果我改变缩放级别,它又像预期的那样工作(直到下一次平移)。我有什么遗漏吗? - Roger Ertesvag
8
关于之前的评论,使用fromLatLngToContainerPixel而不是fromLatLngToDivPixel解决了地图平移后像素位置未更新的问题。 - Roger Ertesvag
1
google.maps.MapCanvasProjection 对象规范,其中包括方法 fromLatLngToContainerPixel(latLng:LatLng) - user664833

34

我认为最简单的方法是忽略Google想要使我们的生活更加困难的愿望,而是编写自己的方法来完成同样的事情,而不是删除和隐藏有用的功能。

这里有一个某人在其他地方发布的函数版本(我现在找不到它了),对我很有效:

fromLatLngToPixel: function (position) {
  var scale = Math.pow(2, Map.getZoom());
  var proj = Map.getProjection();
  var bounds = Map.getBounds();

  var nw = proj.fromLatLngToPoint(
    new google.maps.LatLng(
      bounds.getNorthEast().lat(),
      bounds.getSouthWest().lng()
    ));
  var point = proj.fromLatLngToPoint(position);

  return new google.maps.Point(
    Math.floor((point.x - nw.x) * scale),
    Math.floor((point.y - nw.y) * scale));
},

现在您可以在任何时间和任何地方调用它。我特别需要它用于自定义上下文菜单,而且它的工作非常完美。

编辑: 我还编写了一个反向函数fromPixelToLatLng,它完全相反。它仅基于第一个函数,并应用了一些数学计算:

fromPixelToLatLng: function (pixel) {
  var scale = Math.pow(2, Map.getZoom());
  var proj = Map.getProjection();
  var bounds = Map.getBounds();

  var nw = proj.fromLatLngToPoint(
    new google.maps.LatLng(
      bounds.getNorthEast().lat(),
      bounds.getSouthWest().lng()
    ));
  var point = new google.maps.Point();

  point.x = pixel.x / scale + nw.x;
  point.y = pixel.y / scale + nw.y;

  return proj.fromPointToLatLng(point);
}

2
谷歌的示例:https://developers.google.com/maps/documentation/javascript/examples/map-coordinates - GoTo
1
在你的第一段清楚地表达了Google正在做什么,给你点赞;-) 此外,他将其变成了付费服务,这一点我们完全没有预料到。 - Tomas

21

我对这里的答案不满意。因此,我进行了一些实验,并找到了“最简单”的可行解决方案,它接近于Ralph的答案,但希望更易于理解。(我希望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”标志,在第一次地图idle回调时将其设置为true。然后只有在那之后才执行需要执行的操作。


这应该是问题的被接受答案。非常清晰 - 谢谢! - Andres SK

13
var map;
// Create your map
MyOverlay.prototype = new google.maps.OverlayView();
MyOverlay.prototype.onAdd = function() { }
MyOverlay.prototype.onRemove = function() { }
MyOverlay.prototype.draw = function() { }
function MyOverlay(map) { this.setMap(map); }
var overlay = new MyOverlay(map);
var projection = overlay.getProjection();

我尝试了这段代码,但变量 projection 显示为“未定义”。有任何想法吗?谢谢! - Mathieu Dhondt
6
注意:(这一点曾经让我困扰了半小时)确保在创建地图时创建覆盖层,而不是在需要坐标时(通过fromLatLngToDivPixel)创建。如果你这样做,你会得到未捕获的类型错误:不能调用未定义的方法“fromLatLngToDivPixel”。看起来谷歌有时会异步处理这些东西。 请注意:创建地图时要创建覆盖层,而不是在需要使用坐标(通过fromLatLngToDivPixel)时再创建,否则会出现错误。谷歌有时会以异步方式处理这些内容。 - AlexeyMK
@AlexeyMK,这也困扰了我很久!直到我看到了你的评论。 - shapeshifter

9
要获取MapCanvasProjection,您可以从OverlayView派生一个类并调用getProjection()方法,该方法返回MapCanvasProjection类型。
必须实现onAdd()、draw()和onRemove()以从OverlayView派生。
function MyOverlay(options) {
    this.setValues(options);

    var div = this.div_= document.createElement('div');

    div.className = "overlay";
};

// MyOverlay is derived from google.maps.OverlayView
MyOverlay.prototype = new google.maps.OverlayView;

MyOverlay.prototype.onAdd = function() {

    var pane = this.getPanes().overlayLayer;
    pane.appendChild(this.div_);

}

MyOverlay.prototype.onRemove = function() {
    this.div_.parentNode.removeChild(this.div_);
}

MyOverlay.prototype.draw = function() {
    var projection = this.getProjection();
    var position = projection.fromLatLngToDivPixel(this.getMap().getCenter());

    var div = this.div_;
    div.style.left = position.x + 'px';
    div.style.top = position.y + 'px';
    div.style.display = 'block';
};

然后当你创建地图时

var OverLayMap = new MyOverlay( { map: map } );

对于V2版本,您应该能够从GMap2实例中调用fromLatLngToDivPixel函数。

var centerPoint = map.fromLatLngToDivPixel(map.getCenter());

你是不是把 API v2 和 v3 搞混了? - Jader Dias
1
我认为这是新API的一个很大的问题。它应该有更简单的方法来解决这个问题。 - Jader Dias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接