2

尝试使用OpenLayers(最终)在谷歌地球插件基础地图上加载标记、矢量和 WMS。Google 地球似乎“与其他人相处得不好”。

如果我以“谷歌方式”实例化地图: google.earth.createInstance('map', initCB, failCB);

我得到一个谷歌地图,我可以添加谷歌地标,但我不能将该实例传递给 OpenLayers。

使用以下内容:

map = new OpenLayers.Map('ol-map');
map.addControl(new OpenLayers.Control.LayerSwitcher());

var gphy = new OpenLayers.Layer.Google(
    "Google Physical",
    {type: G_PHYSICAL_MAP}
);
var gmap = new OpenLayers.Layer.Google(
    "Google Streets", // the default
    {numZoomLevels: 20}
);
var ghyb = new OpenLayers.Layer.Google(
    "Google Hybrid",
    {type: G_HYBRID_MAP, numZoomLevels: 20}
);
var gsat = new OpenLayers.Layer.Google(
    "Google Satellite",
    {type: G_SATELLITE_MAP, numZoomLevels: 22}
);
var gearth = new OpenLayers.Layer.Google(
    "Google Earth",
    {type: G_SATELLITE_3D_MAP}
);

map.addLayers([gphy, gmap, ghyb, gsat, gearth]);

map.setCenter(new OpenLayers.LonLat(-120, 32), 5)
addMarker();

这将创建一个具有 5 个 googly 层的基本 OL 地图。我可以看到我添加的任何地图图层时添加的标记,除非选择了齿轮。一旦我加载了谷歌地球地图,它就会“接管”整个 div。所有 OL 控件(例如 LayerSwitcher)都消失了,我无法弄清楚如何从 OL 访问 google earth 实例。

我假设标记仍然存在,但在底图后面。在底图上设置不透明度无效。

问题:

  1. 这是记录在案的限制吗?我找不到任何表明它不应该的东西。
  2. 是否有一种解决方法可以将 OpenLayers 地图/图层实例传递给谷歌地球的 getEarthInstance 调用?或相反亦然?这似乎是两全其美,让我在需要时可以访问 GE API,但我可以将 OL 中的所有 WFS 处理用于大多数任务。

欢迎不成熟的想法。

4

3 回答 3

2

一般来说,OpenLayers 完全不支持 Google Earth 3D 模式。(我是 OpenLayers 的开发人员,我只是通过这个问题才意识到这是可能的。)由于 3D 显示代码的工作方式(通过 3rd 方插件),我无法想象默认的任何方式OpenLayers 工具——用于绘图等——将会起作用:OpenLayers 需要与之集成的部分根本不存在于 3D API 中。

OpenLayers——主要是一个 2D 绘图客户端——不太可能实现将其所有各种调用转换为 Google Maps/Earth API 调用的东西。

OpenLayers 确实支持协议和格式:理论上,这将允许您在与 Google Earth API 等第三方 API 交互时在某种程度上使用 OpenLayers WFS 处理工具链。但是,我希望在这种情况下,您不会从中获得足够的收益来解决您的问题。

简而言之:这是行不通的,也没有简单的解决方案。如果您想要 3D,您可能需要自己构建更多内容。

于 2010-07-21T04:39:49.283 回答
1

我认为这个问题与 Google Maps v2 有关,因为我认为 v3 中没有类型:G_SATELLITE_3D_MAP。

通过google-maps-utility-library-v3 (googleearth.js) 中的脚本支持用于 Google Maps v3 的 Google 地球插件(测试版)

作者@jlivni采取的方法是监听Google Maps v3 添加/删除事件并添加相应的Google Earth Api 对象。我相信类似的方法可以用于 OpenLayers。我是 OpenLayers 的新手,刚刚开始研究这个,但我会在这里发布更新。

我现在唯一可以添加的是关于谷歌地球插件的初始化,这在 v3 中有所不同:

function GoogleEarth( olmap ) {
this.olmap_ = olmap;
this.layer_ = new OpenLayers.Layer.Google(
    "Google Earth",
    {type: google.maps.MapTypeId.SATELLITE, numZoomLevels: 22, visibility: false}
);
this.olmap_.addLayers([ this.layer_ ]);
this.map_ = this.layer_.mapObject;
this.mapDiv_ = this.map_.getDiv();

...
var earthMapType = /** @type {google.maps.MapType} */({
tileSize: new google.maps.Size(256, 256),
maxZoom: 19,
name: this.earthTitle_,
// The alt helps the findMapTypeControlDiv work.
alt: this.earthTitle_,
getTile:
  /**
   * @param {google.maps.Point} tileCoord the tile coordinate.
   * @param {number} zoom the zoom level.
   * @param {Node} ownerDocument n/a.
   * @return {Node} the overlay.
   */
  function(tileCoord, zoom, ownerDocument) {
    var div = ownerDocument.createElement('DIV');
    return div;
  }
});

this.map_.mapTypes.set(GoogleEarth.MAP_TYPE_ID, earthMapType);

this.layer_.type = GoogleEarth.MAP_TYPE_ID;

var that = this;
google.maps.event.addListener(map, 'maptypeid_changed', function() {
  that.mapTypeChanged_();
  }); 
}

令人费解的部分是我们需要为 Google Earth 定义一个新的地图类型,并将该类型添加到 Google Map 对象中。但是,如果我们不创建具有我最初设置为 google.maps.MapTypeId.SATELLITE 的类型的图层,则 Google 地图对象不存在。不是很干净,但至少它让我使用 Google Maps v3 达到与本文作者相同的状态。最后可能有一种方法可以通过修改函数 findMapTypeControlDiv_() 使 OpenLayers 控件可见:

var mapTypeControlDiv = this.findMapTypeControlDiv_();
if (mapTypeControlDiv) {
  this.setZIndexes_(mapTypeControlDiv);
  this.addShim_(mapTypeControlDiv);
}

[更新]

我已经修改了函数 findMapTypeControlDiv_() ,现在我寻找 OpenLayers LayerSwitcher :

GoogleEarth.prototype.findLayerSwitcherDiv_ = function() {
//  var title = 'title="' + this.earthTitle_ + '"';
  var id = 'LayerSwitcher';

  var siblings = this.controlDiv_.parentNode.childNodes;
  for (var i = 0, sibling; sibling = siblings[i]; i++) {
    if (sibling.id.indexOf(id) != -1) {
      return sibling;
    }
  }
};

LayerSwitcher 的 z 索引设置正确,div 显示在顶部,直到调用 google.earth.createInstance(),然后它消失。我会花更多的时间来解决它,它看起来并不难解​​决。

[更新 2]

我已经解决了 LayerSwitcher 面板问题。诀窍是将 Google Earth Plugin div 附加到正确的 div(GMaps 的原始代码将其附加到 Map Controls 数组)。另一个问题是设置 zIndex 以确保 LayerSwitcher 位于顶部。当 GE 插件运行时我仍然遇到问题并且我尝试最小化 LayerSwitcher,对 OpenLayers.Event.stop() 的调用会使 GE 插件崩溃(Chrome)或 LayerSwitcher 消失(IE8)。我想从谷歌分叉原始代码并制作一个适用于 OpenLayers 的 GE 插件层。有人可以建议怎么做吗?谢谢。

无论如何,这是我的最新更改:

GoogleEarth.prototype.findLayerSwitcherDiv_ = function() {
  var id = 'LayerSwitcher';

  var siblings = this.mapDiv_.parentNode.childNodes;
  for (var i = 0, sibling; sibling = siblings[i]; i++) {
    if (sibling.id.indexOf(id) != -1) {
      return sibling;
    }
  }
};

GoogleEarth.prototype.addEarthControl_ = function() {
...
inner.appendChild(earthDiv);
var parentNode = this.findLayerSwitcherDiv_().parentNode;
parentNode.appendChild( control );

...
GoogleEarth.prototype.setZIndexes_ = function(mapTypeControlDiv) {
  var oldIndex = mapTypeControlDiv.style.zIndex;
  var siblings = this.controlDiv_.parentNode.childNodes;
  for (var i = 0, sibling; sibling = siblings[i]; i++) {
    sibling['__gme_ozi'] = sibling.style.zIndex;
    // Sets the zIndex of all controls to be behind Earth.
    sibling.style.zIndex = 0;
  }

  mapTypeControlDiv['__gme_ozi'] = oldIndex;
  this.controlDiv_.style.zIndex = 2000;
  mapTypeControlDiv.style.zIndex = 2001;
};

[更新 3] 我在这里建立了一个 github 项目:https ://github.com/ZiglioUK/GoogleEarth-for-OpenLayers

于 2011-06-22T02:30:26.433 回答
0

我对 OpenLayers 中的不同图层类型不再那么熟悉了,但关键是 Google Earth API 和 Google Maps API 确实是不同的野兽。乍一看,我不明白为什么需要将它添加到 Google Maps 类型(假设我认为是这样)。

正如 Chris 已经暗示的那样,只需将您的 Earth API 集成视为与任何现有 Google 层分开的全新事物;至少据我所知,这些 API 中的语法和概念并没有真正相似到足以让您获得在 OpenLayers 中对现有 Google 地图集成进行子类化的任何优势。

也就是说,我希望 Maps V3/Earth 集成的代码会有所帮助,并且类似于将其与 OpenLayers 集成所需的操作。同时,我看到其他一些人也对此进行了尝试,例如这个 geoExt 示例,您可能也会发现它很有用:http ://dev.geoext.org/sandbox/cmoullet/ux/GoogleEarthPanel/examples/GoogleEarthPanelExample.html

于 2011-06-23T00:14:10.783 回答