Как нарисовать объекты openlayers с помощью базовой карты Google Планета Земля

#openlayers #google-earth-plugin

#openlayers #google-earth-plugin

Вопрос:

Пытаюсь использовать OpenLayers для (в конечном итоге) загрузки маркеров, векторов и WMS поверх базовой карты плагина Google Планета Земля. Похоже, что Google Планета Земля «плохо сочетается с другими».

Если я создам экземпляр карты «способом Google»: google.earth.CreateInstance(‘map’, initCB, failCB);

Я получаю карту Google, на которую я могу добавлять метки Google, но я не могу передать этот экземпляр 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();
  

Это создает базовую карту OL с 5 слоями googly. Я вижу маркер, который добавляю, когда выбирается любой из слоев карты, кроме того, когда выбран параметр gearth. Как только я загружаю карту Google Планета Земля, она «занимает» весь div. Все старые элементы управления, такие как LayerSwitcher, исчезли, и я не смог выяснить, как получить доступ к экземпляру Google Планета Земля из OL.

Я предполагаю, что маркеры все еще присутствуют, но за базовой картой. Установка непрозрачности на базовой карте не влияет.

Вопросы:

  1. Является ли это документированным ограничением? Я не могу найти ничего, что указывало бы, что это должно быть невозможно.
  2. Есть ли обходной путь, при котором я могу передать экземпляр OpenLayers map / layer в вызов getEarthInstance Google Планета Земля? Или наоборот? Кажется, что это было бы лучшим из обоих миров, предоставляя мне доступ к GE API, когда это необходимо, но я мог бы использовать всю обработку WFS в OL для большинства задач.

Приветствуются непродуманные идеи.

Ответ №1:

В целом, OpenLayers абсолютно не поддерживает режим Google Планета Земля 3D. (Я разработчик OpenLayers, и я узнал, что это было возможно, только благодаря этому вопросу.) Из-за того, как работает код 3D-отображения (через сторонний плагин), я не могу представить, как будут работать инструменты OpenLayers по умолчанию — для рисования и т.д. — части, с которыми OpenLayers нужно было бы интегрировать, просто не существуют в 3D API.

OpenLayers — в первую очередь являющийся клиентом 2D-рисования — вряд ли когда-либо реализует что-то, что переводило бы все его различные вызовы в вызовы Google Maps / Earth API.

OpenLayers поддерживает протоколы и форматы: теоретически, это позволило бы вам в некоторой степени использовать набор инструментов обработки OpenLayers WFS при взаимодействии со сторонними API, такими как Google Earth API. Однако я ожидаю, что в этом случае вы не получите от этого достаточной выгоды для решения своей проблемы.

Короче говоря: это не работает, и простого решения не существует. Если вы хотите 3D, вам, вероятно, придется создавать гораздо больше самостоятельно.

Комментарии:

1. Спасибо за отзыв. Я также поддерживаю контакт с парой инженеров Google, поэтому, если я что-нибудь узнаю, буду держать вас в курсе.

2. Вы правы. Мой разговор с инженерами Google не помог с этим, но указал на то, что если вы хотите внедрить плагин Google Планета Земля в пользовательское веб-приложение, локальная копия GE Plugin API (earth_loader_plugin.js ) должны быть загружены и должны быть установлены некоторые переменные среды для настройки ключа API и расположения страницы ошибки для сервера GEE. Пример веб-страницы, загружающей плагин Google Планета Земля и подключающейся к частному серверу GEE, можно посмотреть по адресу gmdemo.keyhole.com/geplugin/gee-basic-example.html для справки.

Ответ №2:

Я думаю, что этот вопрос был связан с Google Maps v2, поскольку я не думаю, что в версии v3 есть тип: G_SATELLITE_3D_MAP.

Плагин Google Планета Земля для Google Maps v3 поддерживается (бета-версия) с помощью скрипта из Google-maps-utility-library-v3 (googleearth.js)

Подход, который использовал автор @jlivni, заключается в прослушивании событий добавления / удаления Google Maps v3 и добавлении соответствующих объектов Google Earth Api. Я полагаю, что аналогичный подход можно было бы использовать с OpenLayers. Я новичок в OpenLayers и только начал изучать это, но я опубликую обновленную информацию здесь.

Единственное, что я могу добавить сейчас, это инициализация плагина Google Планета Земля, которая отличается в версии 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 Планета Земля и добавить этот тип к объекту Google Map. Но объект Google Map не будет существовать, если мы не создадим слой с типом, который я изначально задал в google.maps.MapTypeId.Спутники.
Не очень чисто, но, по крайней мере, это приводит меня к тому же состоянию, что и автора этого поста, с помощью Google Maps v3.
Наконец, может быть способ сделать элементы управления OpenLayers видимыми, изменив функцию findMapTypeControlDiv_():

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

[Обновить]

Я изменил функцию findMapTypeControlDiv_() и теперь вместо нее я ищу LayerSwitcher OpenLayers:

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

z-индекс LayerSwitcher установлен правильно, и div отображается сверху до тех пор, пока не будет вызван google.earth.CreateInstance(), после чего он исчезает. Я потрачу на это еще немного времени, похоже, это не так уж сложно решить.

[Обновление 2]

Я решил проблему с панелью LayerSwitcher. Хитрость заключалась в том, чтобы прикрепить div плагина Google Планета Земля к соответствующему div (исходный код GMaps прикрепляет его к массиву элементов управления картой). Другой проблемой была настройка zIndex, чтобы убедиться, что LayerSwitcher находится сверху. У меня все еще возникает проблема при запуске плагина GE, и я пытаюсь минимизировать LayerSwitcher, вызов OpenLayers.Событие.stop() приводит к сбою плагина GE (Chrome) или исчезновению LayerSwitcher (IE8). Я хотел бы использовать исходный код из Google и создать слой плагина GE, который работает на OpenLayers. Кто-нибудь может подсказать, как это сделать? Спасибо.

В любом случае, вот мои последние изменения:

 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

Комментарии:

1. привет, URL-адрес обновления 4 возвращает 404, также пробованное «обновление 3», похоже, устарело. у вас есть рабочий набор?

Ответ №3:

Я больше не знаком с различными типами слоев в OpenLayers, но главное в том, что API Google Earth и API Google Maps — это действительно разные устройства. На первый взгляд я не понимаю, зачем вам нужно добавлять это в тип Google Maps (предполагая, что это то, что я думаю).

Как уже подразумевал Крис, просто относитесь к своей интеграции с Earth API как к совершенно новой вещи, отдельной от любых существующих Google layers; синтаксис и концепции в этих API на самом деле недостаточно похожи, чтобы вы могли получить какое-либо преимущество от подкласса существующей интеграции Google Maps в OpenLayers, по крайней мере, насколько я могу судить.

Тем не менее, я надеюсь, что код для интеграции Maps V3 / Earth будет полезным и аналогичным тому, что вам нужно сделать, чтобы интегрировать его с OpenLayers. Между тем, я видел, как некоторые другие люди также пытались это сделать, например, этот пример GeoExt, который вы также можете счесть полезным: http://dev.geoext.org/sandbox/cmoullet/ux/GoogleEarthPanel/examples/GoogleEarthPanelExample.html