Все готово!

Прежде чем приступить к разработке, ознакомьтесь с документацией для разработчиков.

Активация Google Maps JavaScript API

Чтобы помочь вам освоиться, мы покажем, как выполнить некоторые необходимые действия в консоли разработчика Google:

  1. Создание или выбор проекта
  2. Активация Google Maps JavaScript API и связанных служб
  3. Создание соответствующих ключей

Типы карт

Типы карт

Этот документ описывает типы карт, которые можно отображать с помощьюGoogle Maps JavaScript API. API использует объект MapType для хранения информации об этих картах. MapType – это интерфейс, определяющий отображение и использование листов карты, а также преобразование координат на экране в географические координаты карты. Каждый объект MapType должен содержать несколько методов для обработки получения и удаления листов карты, а также свойства, определяющие его визуальное поведение.

Внутренняя структура типов карт в Maps JavaScript API – довольно сложная тема. Большинство разработчиков могут просто использовать базовые типы карт, указанные ниже. Вы также можете определять собственные листы карты, используя собственные типы карт или изменять представление существующих типов карт, используя стили карт. При использовании собственных типов карт нужно понимать, как изменять реестр типов карт.

Базовые типы карт

В интерфейсе Google Maps JavaScript API представлено четыре типа карт. Помимо знакомых "раскрашенных" листов дорожных карт, Maps JavaScript API поддерживает также и другие типы карт.

В Maps JavaScript API доступны следующие типы карт.

  • roadmap – стандартное представление дорожной карты. Этот тип карты используется по умолчанию.
  • satellite – карта из спутниковых снимков Google Earth.
  • hybrid – сочетание обычной и спутниковой карты.
  • terrain – физическая карта на основе данных о ландшафте.

Чтобы изменить используемый тип карты, нужно изменить свойство mapTypeId объекта Map. Это можно сделать или в конструкторе путем изменения его объекта Map options, или посредством вызова метода setMapTypeId() для этой карты. Свойство mapTypeID по умолчанию имеет значение roadmap.

Установка свойства mapTypeId при создании карты:

var myLatlng = new google.maps.LatLng(-34.397, 150.644);
var mapOptions = {
  zoom: 8,
  center: myLatlng,
  mapTypeId: 'satellite'
};
var map = new google.maps.Map(document.getElementById('map'),
    mapOptions);

Динамическое изменение свойства mapTypeId:

map.setMapTypeId('terrain');

Обратите внимание, что фактически вы устанавливаете не сам тип карты, а свойство карты mapTypeId, которое ссылается на MapType с помощью идентификатора. В Maps JavaScript API для управления этими ссылками используется реестр типов карт, описанный ниже.

Изображения под углом 45°

Google Maps JavaScript API поддерживает изображения под углом 45° для определенных мест. Эти изображения в высоком разрешении показывают изображение в перспективе по отношению к каждому основному направлению (север, юг, восток, запад). Для поддерживаемых типов карт эти изображения доступны в более крупном масштабе.

На следующем изображении показана перспектива тротуара в Санта-Круз (Калифорния, США) под углом 45°:

Типы карт satellite и hybrid поддерживают изображение под углом 45° при сильном увеличении там, где эта возможность доступна. Если пользователь увеличивает область, для которой существуют такие изображения, представления карт этих типов автоматически изменяются следующим образом:

  • Спутниковые или гибридные изображения заменяются изображениями под углом 45°, отцентрированными по текущему местоположению. По умолчанию такие изображения ориентированы на север. Если пользователь уменьшит масштаб, на карте снова появятся используемые по умолчанию спутниковые или гибридные изображения.
  • Элемент управления поворотом позволяет регулировать наклон и вращение карт. Если параметр rotateControl имеет значение true, для изображений под углом 45° отображается элемент управления наклоном. Этот элемент управления позволяет пользователю наклонять изображение до угла 45°.
  • Когда изображение наклонено, на экране появляется стрелка, с помощью которой пользователи могут поворачивать экран на 90° по часовой стрелке.

При уменьшении масштаба карты с изображением под углом 45° все эти изменения сбрасываются и восстанавливается первоначальный тип карты.

Включение и отключение изображений под углом 45°

Вы можете отключить изображения под углом 45°, вызвав метод setTilt(0) для объекта Map. Чтобы включить изображения под углом 45° для поддерживаемых типов карт, нужно вызвать метод setTilt(45).

Метод getTilt() объекта Map всегда отражает текущий наклон изображения на карте. Если установить для изображения наклон, а затем убрать его (например, уменьшив масштаб карты), метод getTilt() карты будет возвращать значение 0.

В следующем примере отображается карта центра Портленда (Орегон, США) под углом 45°:

function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 36.964, lng: -122.015},
    zoom: 18,
    mapTypeId: 'satellite'
  });
  map.setTilt(45);
}
<div id="map"></div>
/* 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;
}
 <!-- Replace the value of the key parameter with your own API key. -->
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap">
</script>
function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 36.964, lng: -122.015},
    zoom: 18,
    mapTypeId: 'satellite'
  });
  map.setTilt(45);
}

Просмотр примера (aerial-simple.html).

Вращение изображения под углом 45°

Изображение под углом 45° фактически состоит из набора изображений для каждого основного направления (север, юг, восток, запад). Когда на карте отображаются изображения под углом 45°, их можно сориентировать по одному из основных направлений, вызвав метод setHeading() для объекта Map и передав ему числовое значение, соответствующее градусам отклонения от севера.

В следующем примере показана карта, составленная по аэрофотоснимкам, которая автоматически поворачивается каждые 3 секунды при нажатии кнопки:

var map;

function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 45.518, lng: -122.672},
    zoom: 18,
    mapTypeId: 'satellite',
    heading: 90,
    tilt: 45
  });
}

function rotate90() {
  var heading = map.getHeading() || 0;
  map.setHeading(heading + 90);
}

function autoRotate() {
  // Determine if we're showing aerial imagery.
  if (map.getTilt() !== 0) {
    window.setInterval(rotate90, 3000);
  }
}
<div id="floating-panel"><input type="button" value="Auto Rotate" onclick="autoRotate();"></div>
<div id="map"></div>
/* 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;
}
#floating-panel {
  position: absolute;
  top: 10px;
  left: 25%;
  z-index: 5;
  background-color: #fff;
  padding: 5px;
  border: 1px solid #999;
  text-align: center;
  font-family: 'Roboto','sans-serif';
  line-height: 30px;
  padding-left: 10px;
}
 <!-- Replace the value of the key parameter with your own API key. -->
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap">
</script>
var map;

function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 45.518, lng: -122.672},
    zoom: 18,
    mapTypeId: 'satellite',
    heading: 90,
    tilt: 45
  });
}

function rotate90() {
  var heading = map.getHeading() || 0;
  map.setHeading(heading + 90);
}

function autoRotate() {
  // Determine if we're showing aerial imagery.
  if (map.getTilt() !== 0) {
    window.setInterval(rotate90, 3000);
  }
}

Просмотр примера (aerial-rotation.html).

Изменение реестра типа карт

mapTypeId – идентификатор строки, используемый для привязки уникального значения к типу MapType. Каждый объект Map ведет реестр MapTypeRegistry, содержащий набор доступных типов MapType для этой карты. Этот реестр используется для выбора типов карт, которые доступны, например, для элемента управления MapType карты.

Считывание не выполняется непосредственно из реестра типов карт. Вместо этого реестр изменяется посредством добавления собственных типов карт и их привязки к выбранному идентификатору строки. Изменять или модифицировать базовые типы карт нельзя (хотя их можно убирать с карты, изменяя вид параметра mapTypeControlOptions).

В следующем примере кода показано, как настроить карты для отображения только двух типов карт, используя параметр mapTypeControlOptions, и как изменить реестр для добавления связи с этим идентификатором в фактическую реализацию интерфейса MapType. Примечание. Мы целенаправленно не документировали создание собственного типа карты в приведенном выше примере кода. В разделах Стили карт и Собственные типы карт ниже см. дополнительную информацию о создании типов карт.

// Modify the control to only display two maptypes, the
// default ROADMAP and the custom 'mymap'.
// Note that because this is simply an association, we
// don't need to modify the MapTypeRegistry beforehand.

var MY_MAPTYPE_ID = 'mymaps';

var mapOptions = {
  zoom: 12,
  center: brooklyn,
  mapTypeControlOptions: {
     mapTypeIds: ['roadmap', MY_MAPTYPE_ID]
  },
  mapTypeId: MY_MAPTYPE_ID
};

// Create our map. This creation will implicitly create a
// map type registry.
map = new google.maps.Map(document.getElementById('map'),
    mapOptions);

// Create your custom map type using your own code.
// (See below.)
var myMapType = new MyMapType();

// Set the registry to associate 'mymap' with the
// custom map type we created, and set the map to
// show that map type.
map.mapTypes.set(MY_MAPTYPE_ID, myMapType);

Стили карт

StyledMapType позволяет настроить вид стандартных базовых карт Google, изменяя стиль изображения таких элементов, как дороги, парки и районы застройки.

Дополнительные сведения о StyledMapType см. в руководстве по стилизации карт.

Собственные типы карт

Теперь Google Maps JavaScript API поддерживает отображение собственных типов карт и управление ими, позволяя использовать на картах собственные изображения или мозаичные наложения.

В Maps JavaScript API существует несколько возможных реализаций типа карт.

  • Стандартные наборы листов карт, состоящие из изображений, которые в совокупности представляют собой полноценные карты. Эти наборы листов также называются базовыми типами карт. Эти типы карт похожи на существующие типы карт по умолчанию: roadmap, satellite, hybrid и terrain. Вы можете добавить собственный тип в массив mapTypes карты, чтобы пользовательский интерфейс в Maps JavaScript API мог интерпретировать ваш собственный тип карты в качестве стандартного (например, включив его в элемент управления MapType).
  • Мозаичные наложения изображения, отображаемые поверх существующих базовых типов карт. Обычно эти типы карт дополняют существующие типы и используются для отображения дополнительной информации. Их использование часто ограничено определенными местами и/или масштабом. Мозаичные наложения могут быть прозрачными, благодаря чему можно добавлять элементы на существующие карты.
  • Неграфические типы карт, позволяющие изменять отображение информации на карте на самом фундаментальном уровне.

Каждый из этих вариантов основан на создании класса, реализующего интерфейс MapType. Кроме того, класс ImageMapType имеет встроенные функции, упрощающие создание изображений MapType.

Прежде чем мы подробно расскажем о классах, реализующих MapType, необходимо понять, каким образом в Google Maps определяются координаты и выбирается часть карты для отображения. Вам нужно будет реализовать похожую логику для любых базовых типов и слоев MapType.

Координаты на карте

Существует несколько систем координат, используемых в Google Maps JavaScript API.

  • Значения широты и долготы, обеспечивающие уникальную идентификацию любой географической точки. (Google использует стандарт всемирной геодезической системы WGS84.)
  • Мировые координаты, обеспечивающие уникальную идентификацию точки на карте.
  • Координаты листа карты, которые указывают конкретный лист на карте при определенном масштабе.

Мировые координаты

Когда Google Maps JavaScript API требуется преобразовать географическую точку в точку на карте (экране), ему прежде всего нужно преобразовать значения широты и долготы в "мировые" координаты. Это преобразование выполняется с помощью проекции карты. Для этой цели в Google Maps используется проекция Меркатора. Также вы можете определить собственную проекцию посредством реализации интерфейса google.maps.Projection. (Следует отметить, что интерфейсы в Maps JavaScript API не являются классами, от которых вы наследуете подклассы, а просто указывают на классы, которые вы определяете самостоятельно.)

Для удобства расчета координат в пикселях (см. ниже) мы предполагаем, что карта с уровнем масштабирования 0 представляет собой один лист базового размера. Затем мы определяем мировые координаты по отношению к пиксельным координатам на уровне масштабирования 0, используя проекцию для преобразования значений широты и долготы в позиции пикселей на базовом листе. Мировая координата – это значение с плавающей запятой, измеряемое от исходной точки проекции карты до определенного места. Поскольку это значение с плавающей запятой, оно может быть намного более точным, чем текущее разрешение отображаемой карты. Другими словами, мировые координаты не зависят от текущего уровня масштабирования.

Мировые координаты в Google Maps измеряются от исходной точки проекции Меркатора (северо-западный угол карты при 180 градусах долготы и примерно 85 градусах широты) и увеличиваются на восток (вправо) по оси x и на юг (вниз) по оси y. Поскольку базовый лист Google Maps в проекции Меркатора имеет размеры 256 x 256 пикселей, полезное пространство мировых координат составляет {0-256}, {0-256} (см. ниже).

Следует отметить, что участок карты в проекции Меркатора имеет определенную ширину по долготе, но неопределенную высоту по широте. Мы "вырезаем" базовые изображения карты, используя проекцию Меркатора на широте примерно +/- 85 градусов, чтобы сделать получившуюся форму карты квадратной, что упростит логику выбора листов. Следует отметить, что проекция может выдавать мировые координаты за пределами полезной области координат карты, например, при выводе изображения возле полюсов.

Пиксельные координаты

Мировые координаты отражают абсолютные положения в указанной проекции, но для определения пиксельного смещения при заданном уровне масштабирования их нужно преобразовать в пиксельные координаты. Эти пиксельные координаты рассчитываются с использованием следующей формулы:

pixelCoordinate = worldCoordinate * 2zoomLevel

По вышеуказанному уравнению можно заметить, что каждый следующий уровень масштабирования в два раза больше предыдущего по осям x и y. Таким образом, каждый следующий уровень масштабирования имеет в четыре раза более высокое разрешение, чем предыдущий. Например, на уровне масштабирования 1 карта содержит 4 листа размером 256x256 пикселей, т. е. пиксельная область составляет 512x512. На уровне масштабирования 19 каждый пиксель x и y на карте можно задать, указав значение между 0 и 256 * 219.

Поскольку мировые координаты основаны на размере листа карты, целочисленная часть координат пикселей идентифицирует конкретный пиксель в этой точке при текущем уровне масштабирования. При уровне масштабирования 0 пиксельные координаты эквивалентны мировым координатам.

Теперь у нас есть способ точно обозначить каждое положение на карте на каждом уровне масштабирования. Google Maps JavaScript API создает область просмотра для заданного центра соответствующего уровня масштабирования карты (LatLng) и размера содержащего его элемента DOM, после чего преобразует границы этой области в пиксельные координаты. Затем API логически определяет все листы карты, лежащие в пределах указанных пиксельных границ. Ссылка на каждый из этих листов карты передается с использованием координат листа, что значительно упрощает отображение изображений на карте.

Координаты листа

Google Maps JavaScript API не может загружать все изображения карт на самых высоких уровнях масштабирования, которые используются чаще всего. Вместо этого Maps JavaScript API разбивает изображения на каждом уровне масштабирования на набор листов карты, которые логически упорядочиваются понятным приложению образом. При прокрутке карты к новому местоположению или при изменении уровня масштабирования Maps JavaScript API использует пиксельные координаты, чтобы определить необходимые листы, и преобразует эти значения в список листов, которые нужно получить. Эти координаты листов присваиваются с использованием схемы, логически упрощающей определение листов, содержащих изображения для любой указанной точки.

Листы в Google Maps нумеруются тем же способом, что и пиксели. В проекции Меркатора, реализованной Google, исходный лист всегда находится в северо-западном углу карты, при этом значения x увеличиваются в направлении с запада на восток, а значения y увеличиваются в направлении с севера на юг. Листы индексируются с использованием координат x,y относительно этой точки. Например, на уровне масштабирования 2, когда Земля делится на 16 листов, каждый лист обозначается уникальными координатами x,y:

Обратите внимание, что если разделить пиксельные координаты на размер листа и взять целую часть результата, получится координата листа на текущем уровне масштабирования.

В следующем примере отображаются координаты Чикаго (Иллинойс, США) для разных уровней масштабирования – значения LatLng, мировые координаты, пиксельные координаты и координаты листа:

Просмотр примера (map-coordinates.html)

Интерфейс MapType

В собственных типах карт должен быть реализован интерфейс MapType. Этот интерфейс указывает определенные свойства и методы, позволяющие API отправлять запросы к вашим типам карт, когда API требуется отобразить листы карты для текущей области просмотра и текущего уровня увеличения. Ваше приложение обрабатывает эти запросы и определяет, какой лист нужно загрузить.

Примечание. Для реализации этого интерфейса вы можете создать собственный класс или (если у вас есть совместимые изображения) использовать класс ImageMapType, в котором этот интерфейс уже реализован.

Классы, реализующие интерфейс MapType, требуют, чтобы вы определили следующие свойства и задали их значения:

  • tileSize (обязательное) – указывает размер листа (типа google.maps.Size). Лист должен иметь прямоугольную форму, но не обязательно квадратную.
  • maxZoom (обязательное) – указывает максимальный уровень масштабирования, на котором должны отображаться листы этого типа карт.
  • minZoom (необязательное) – указывает минимальный уровень масштабирования, на котором должны отображаться листы этого типа карт. По умолчанию это значение равняется 0, что означает отсутствие минимального уровня масштабирования.
  • name (необязательное) – указывает имя этого типа карт. Это свойство необходимо только в том случае, если вы хотите, чтобы этот тип карт можно было выбирать в элементе управления MapType. (Дополнительную информацию см. в разделе Добавление элементов управления MapType ниже.)
  • alt (необязательное) – указывает альтернативный текст для этого типа карт, всплывающий при наведении курсора. Это свойство необходимо только в том случае, если вы хотите, чтобы этот тип карт можно было выбирать в элементе управления MapType. (Дополнительную информацию см. в разделе Добавление элементов управления MapType ниже.)

Кроме того, классы, в которых реализован интерфейс MapType, должны содержать реализацию следующих методов:

  • getTile() (обязательный) – вызывается, когда API обнаруживает необходимость отображения новых листов карты для указанной области просмотра. Метод getTile() должен иметь следующий синтаксис:

    getTile(tileCoord:Point,zoom:number,ownerDocument:Document):Node

    API определяет, требуется ли вызывать метод getTile(), основываясь на свойствах tileSize, minZoom и maxZoom объекта MapType, а также по текущей области просмотра и уровню масштабирования. Обработчик этого метода должен возвращать элемент HTML с учетом переданных координат, уровня масштабирования и элемента DOM, к которому нужно добавить изображение листа.

  • releaseTile() (необязательный) – вызывается, когда API обнаруживает необходимость удаления листа карты, поскольку этот лист не попадает в область просмотра. Этот метод имеет следующий синтаксис:

    releaseTile(tile:Node)

    Обычно ваше приложение должно обрабатывать удаление всех элементов, прикрепленных к листам карты при их добавлении на карту. Например, если вы прикрепили блоки прослушивания событий к мозаичным наложениям карты, их нужно удалить с помощью этого метода.

Метод getTile() является основным инструментом для определения листов, которые следует загружать в указанную область просмотра.

Базовые типы карт

Типы карт, создаваемые таким способом, могут быть отдельными или сочетаться с другими типами карт как наложения. Отдельные типы карт называются базовыми. API может обращаться с такими собственными объектами MapType, как и с другими существующими базовыми типами карт (ROADMAP, TERRAIN и т. д.). Для этого вы должны добавить собственный объект MapType в свойство mapTypes объекта Map. Это свойство имеет тип MapTypeRegistry.

Следующий код создает базовый объект MapType для отображения координат листа карты и рисует контуры листов:

/*
 * This demo demonstrates how to replace default map tiles with custom imagery.
 * In this case, the CoordMapType displays gray tiles annotated with the tile
 * coordinates.
 *
 * Try panning and zooming the map to see how the coordinates change.
 */

/**
 * @constructor
 * @implements {google.maps.MapType}
 */
function CoordMapType(tileSize) {
  this.tileSize = tileSize;
}

CoordMapType.prototype.maxZoom = 19;
CoordMapType.prototype.name = 'Tile #s';
CoordMapType.prototype.alt = 'Tile Coordinate Map Type';

CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
  var div = ownerDocument.createElement('div');
  div.innerHTML = coord;
  div.style.width = this.tileSize.width + 'px';
  div.style.height = this.tileSize.height + 'px';
  div.style.fontSize = '10';
  div.style.borderStyle = 'solid';
  div.style.borderWidth = '1px';
  div.style.borderColor = '#AAAAAA';
  div.style.backgroundColor = '#E5E3DF';
  return div;
};

function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 10,
    center: {lat: 41.850, lng: -87.650},
    streetViewControl: false,
    mapTypeId: 'coordinate',
    mapTypeControlOptions: {
      mapTypeIds: ['coordinate', 'roadmap'],
      style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
    }
  });

  map.addListener('maptypeid_changed', function() {
    var showStreetViewControl = map.getMapTypeId() !== 'coordinate';
    map.setOptions({
      streetViewControl: showStreetViewControl
    });
  });

  // Now attach the coordinate map type to the map's registry.
  map.mapTypes.set('coordinate',
                   new CoordMapType(new google.maps.Size(256, 256)));
}
<div id="map"></div>
/* 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;
}
 <!-- Replace the value of the key parameter with your own API key. -->
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap">
</script>
/*
 * This demo demonstrates how to replace default map tiles with custom imagery.
 * In this case, the CoordMapType displays gray tiles annotated with the tile
 * coordinates.
 *
 * Try panning and zooming the map to see how the coordinates change.
 */

/**
 * @constructor
 * @implements {google.maps.MapType}
 */
function CoordMapType(tileSize) {
  this.tileSize = tileSize;
}

CoordMapType.prototype.maxZoom = 19;
CoordMapType.prototype.name = 'Tile #s';
CoordMapType.prototype.alt = 'Tile Coordinate Map Type';

CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
  var div = ownerDocument.createElement('div');
  div.innerHTML = coord;
  div.style.width = this.tileSize.width + 'px';
  div.style.height = this.tileSize.height + 'px';
  div.style.fontSize = '10';
  div.style.borderStyle = 'solid';
  div.style.borderWidth = '1px';
  div.style.borderColor = '#AAAAAA';
  div.style.backgroundColor = '#E5E3DF';
  return div;
};

function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 10,
    center: {lat: 41.850, lng: -87.650},
    streetViewControl: false,
    mapTypeId: 'coordinate',
    mapTypeControlOptions: {
      mapTypeIds: ['coordinate', 'roadmap'],
      style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
    }
  });

  map.addListener('maptypeid_changed', function() {
    var showStreetViewControl = map.getMapTypeId() !== 'coordinate';
    map.setOptions({
      streetViewControl: showStreetViewControl
    });
  });

  // Now attach the coordinate map type to the map's registry.
  map.mapTypes.set('coordinate',
                   new CoordMapType(new google.maps.Size(256, 256)));
}

Просмотр примера (maptype-base.html).

Типы наложений

Некоторые типы карт создаются для наложения на существующие типы карт. Такие типы карт могут иметь прозрачные слои с указанием достопримечательностей или дополнительных данных для пользователей.

В таких случаях нежелательно обращаться с типом карты, как с отдельной сущностью. Вместо этого вы можете добавить его напрямую в существующий объект MapType, используя свойство overlayMapTypes объекта Map. Это свойство содержит массив MVCArray объектов MapType. Прорисовка всех типов карт (базовых и наложений) выполняется на слое mapPane. Наложения отображаются поверх базовых карт, к которым они прикреплены, в том же порядке, в каком они перечислены в массиве Map.overlayMapTypes.

Следующий пример идентичен предыдущему примеру за исключением того, что в нем мы создали мозаичное наложение MapType, накладываемое поверх карты типа ROADMAP:

/*
 * This demo illustrates the coordinate system used to display map tiles in the
 * API.
 *
 * Tiles in Google Maps are numbered from the same origin as that for
 * pixels. For Google's implementation of the Mercator projection, the origin
 * tile is always at the northwest corner of the map, with x values increasing
 * from west to east and y values increasing from north to south.
 *
 * Try panning and zooming the map to see how the coordinates change.
 */

/** @constructor */
function CoordMapType(tileSize) {
  this.tileSize = tileSize;
}

CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
  var div = ownerDocument.createElement('div');
  div.innerHTML = coord;
  div.style.width = this.tileSize.width + 'px';
  div.style.height = this.tileSize.height + 'px';
  div.style.fontSize = '10';
  div.style.borderStyle = 'solid';
  div.style.borderWidth = '1px';
  div.style.borderColor = '#AAAAAA';
  return div;
};

function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 10,
    center: {lat: 41.850, lng: -87.650}
  });

  // Insert this overlay map type as the first overlay map type at
  // position 0. Note that all overlay map types appear on top of
  // their parent base map.
  map.overlayMapTypes.insertAt(
      0, new CoordMapType(new google.maps.Size(256, 256)));
}
<div id="map"></div>
/* 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;
}
 <!-- Replace the value of the key parameter with your own API key. -->
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap">
</script>
/*
 * This demo illustrates the coordinate system used to display map tiles in the
 * API.
 *
 * Tiles in Google Maps are numbered from the same origin as that for
 * pixels. For Google's implementation of the Mercator projection, the origin
 * tile is always at the northwest corner of the map, with x values increasing
 * from west to east and y values increasing from north to south.
 *
 * Try panning and zooming the map to see how the coordinates change.
 */

/** @constructor */
function CoordMapType(tileSize) {
  this.tileSize = tileSize;
}

CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
  var div = ownerDocument.createElement('div');
  div.innerHTML = coord;
  div.style.width = this.tileSize.width + 'px';
  div.style.height = this.tileSize.height + 'px';
  div.style.fontSize = '10';
  div.style.borderStyle = 'solid';
  div.style.borderWidth = '1px';
  div.style.borderColor = '#AAAAAA';
  return div;
};

function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 10,
    center: {lat: 41.850, lng: -87.650}
  });

  // Insert this overlay map type as the first overlay map type at
  // position 0. Note that all overlay map types appear on top of
  // their parent base map.
  map.overlayMapTypes.insertAt(
      0, new CoordMapType(new google.maps.Size(256, 256)));
}

Просмотр примера (maptype-overlay.html).

Типы мозаичных карт

Реализация объекта MapType как базового типа карты может требовать много времени и ресурсов. API предоставляет специальный класс, реализующий интерфейс MapType для наиболее распространенных типов карт, которые состоят из листов, составленных из отдельных файлов изображений.

Этот класс, называемый ImageMapType, строится с использованием спецификации объекта ImageMapTypeOptions, определяющей следующие обязательные свойства:

  • tileSize (обязательное) – указывает размер листа (типа google.maps.Size). Лист должен иметь прямоугольную форму, но не обязательно квадратную.
  • getTileUrl (обязательное) – указывает функцию (обычно литерал функции в строке) для обработки выбора подходящего листа изображения на основе указанных мировых координат и уровня масштабирования.

Следующий код показывает базовую реализацию ImageMapType с использованием листов карт Google для Луны. В этом примере используется функция нормализации для повторения листов по оси x карты, но не по оси y.

function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 0, lng: 0},
    zoom: 1,
    streetViewControl: false,
    mapTypeControlOptions: {
      mapTypeIds: ['moon']
    }
  });

  var moonMapType = new google.maps.ImageMapType({
    getTileUrl: function(coord, zoom) {
        var normalizedCoord = getNormalizedCoord(coord, zoom);
        if (!normalizedCoord) {
          return null;
        }
        var bound = Math.pow(2, zoom);
        return '//mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw' +
            '/' + zoom + '/' + normalizedCoord.x + '/' +
            (bound - normalizedCoord.y - 1) + '.jpg';
    },
    tileSize: new google.maps.Size(256, 256),
    maxZoom: 9,
    minZoom: 0,
    radius: 1738000,
    name: 'Moon'
  });

  map.mapTypes.set('moon', moonMapType);
  map.setMapTypeId('moon');
}

// Normalizes the coords that tiles repeat across the x axis (horizontally)
// like the standard Google map tiles.
function getNormalizedCoord(coord, zoom) {
  var y = coord.y;
  var x = coord.x;

  // tile range in one direction range is dependent on zoom level
  // 0 = 1 tile, 1 = 2 tiles, 2 = 4 tiles, 3 = 8 tiles, etc
  var tileRange = 1 << zoom;

  // don't repeat across y-axis (vertically)
  if (y < 0 || y >= tileRange) {
    return null;
  }

  // repeat across x-axis
  if (x < 0 || x >= tileRange) {
    x = (x % tileRange + tileRange) % tileRange;
  }

  return {x: x, y: y};
}
<div id="map"></div>
/* 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;
}
 <!-- Replace the value of the key parameter with your own API key. -->
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap">
</script>
function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 0, lng: 0},
    zoom: 1,
    streetViewControl: false,
    mapTypeControlOptions: {
      mapTypeIds: ['moon']
    }
  });

  var moonMapType = new google.maps.ImageMapType({
    getTileUrl: function(coord, zoom) {
        var normalizedCoord = getNormalizedCoord(coord, zoom);
        if (!normalizedCoord) {
          return null;
        }
        var bound = Math.pow(2, zoom);
        return '//mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw' +
            '/' + zoom + '/' + normalizedCoord.x + '/' +
            (bound - normalizedCoord.y - 1) + '.jpg';
    },
    tileSize: new google.maps.Size(256, 256),
    maxZoom: 9,
    minZoom: 0,
    radius: 1738000,
    name: 'Moon'
  });

  map.mapTypes.set('moon', moonMapType);
  map.setMapTypeId('moon');
}

// Normalizes the coords that tiles repeat across the x axis (horizontally)
// like the standard Google map tiles.
function getNormalizedCoord(coord, zoom) {
  var y = coord.y;
  var x = coord.x;

  // tile range in one direction range is dependent on zoom level
  // 0 = 1 tile, 1 = 2 tiles, 2 = 4 tiles, 3 = 8 tiles, etc
  var tileRange = 1 << zoom;

  // don't repeat across y-axis (vertically)
  if (y < 0 || y >= tileRange) {
    return null;
  }

  // repeat across x-axis
  if (x < 0 || x >= tileRange) {
    x = (x % tileRange + tileRange) % tileRange;
  }

  return {x: x, y: y};
}

Просмотр примера (maptype-image.html).

Проекции

Земля представляет собой трехмерную сферу (приближенно), тогда как карта является плоской двухмерной поверхностью. Карта, отображаемая Google Maps JavaScript API, как и любая двухмерная карта Земли, представляет собой проекцию этой сферы на плоскую поверхность. Проще говоря, проекцию можно определить как преобразование значений широты и долготы в координаты на проекции карты.

Проекции в Maps JavaScript API должны использовать интерфейс Projection. Реализация интерфейса Projection должна обеспечивать не просто сопоставление одной системы координат с другой, но и двустороннее сопоставление. Это означает, что вы должны определить преобразование географических координат (LatLng) в систему мировых координат интерфейса Projection и наоборот. Google Maps API использует проекцию Меркатора для создания карт из географических данных и преобразования событий карты в географические координаты. Вы можете получить эту проекцию, вызвав метод getProjection() для объекта Map (или любого стандартного базового объекта MapType). В большинстве случаев достаточно использовать стандартный интерфейс Projection, но вы также можете создать и использовать собственную проекцию для своего приложения.

Реализация проекции

При реализации собственной проекции вам потребуется определить:

  • Формулу привязки координат широты и долготы к картезианской плоскости и наоборот. (Интерфейс Projection поддерживает только преобразования в прямолинейные координаты.)
  • Базовый размер листа карты. Все листы должны быть прямоугольными.
  • Размер карты "карта мира" использует базовый набор листов с уровнем увеличения 0. Следует отметить, что для карт, состоящих из одного листа с уровнем увеличения 0, размер мира равен базовому размеру листа.

Преобразования координат в проекциях

Каждая проекция предоставляет два метода для преобразования географических координат в мировые и наоборот:

  • Метод Projection.fromLatLngToPoint() преобразует значение LatLng в мировые координаты. Этот метод используется для размещения наложений на карте (и для расположения самой карты).
  • Метод Projection.fromPointToLatLng() преобразует мировые координаты в значение LatLng. Этот метод используется для преобразования событий на карте (например, нажатий мыши) в географические координаты.

В Google Maps предполагается, что проекции являются прямолинейными.

Обычно проекции используются для двух случаев: создания карты мира и создания карты местности. В первом случае необходимо убедиться, что ваша проекция является прямолинейной и нормальной для всех значений долготы. Некоторые проекции (особенно конические) могут быть "локально нормальными" (т. е. быть ориентированными на север), но отклоняться от истинного севера, например, при большом удалении карты относительно некоторой эталонной долготы. Вы можете использовать такую проекцию локально, но при этом следует помнить, что проекция обязательно будет неточной, и ошибки преобразования будут все более заметны при отклонении от эталонной долготы.

Выбор листа карты в проекциях

Проекции применяются не только для определения положения мест и наложений, но и для позиционирования самих листов карты. Google Maps JavaScript API использует для прорисовки базовых карт интерфейс MapType, который должен декларировать как свойство projection для идентификации проекции карты, так и метод getTile() для получения листов карты по значениям координат листов. Координаты листа указываются на основе базового размера листа (который должен иметь прямоугольную форму) и "размера мира" вашей карты, т. е. пиксельного размера карты при уровне масштабирования 0. (На картах, состоящих из одного листа с уровнем масштабирования 0, размер листа и размер мира совпадают.)

Базовый размер листа определяется с помощью свойства tileSize объекта MapType. Размер мира косвенно определяется методами fromLatLngToPoint() и fromPointToLatLng() вашей проекции.

Поскольку выбор изображения зависит от переданных значений, рекомендуется дать изображениям имена, которые можно выбрать программным способом по переданным значениям, например, map_zoom_tileX_tileY.png.

В следующем примере определяется тип ImageMapType с помощью проекции Галла-Петерса:

// This example defines an image map type using the Gall-Peters
// projection.
// https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection

function initMap() {
  // Create a map. Use the Gall-Peters map type.
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 0,
    center: {lat: 0, lng: 0},
    mapTypeControl: false
  });

  initGallPeters();
  map.mapTypes.set('gallPeters', gallPetersMapType);
  map.setMapTypeId('gallPeters');

  // Show the lat and lng under the mouse cursor.
  var coordsDiv = document.getElementById('coords');
  map.controls[google.maps.ControlPosition.TOP_CENTER].push(coordsDiv);
  map.addListener('mousemove', function(event) {
    coordsDiv.textContent =
        'lat: ' + Math.round(event.latLng.lat()) + ', ' +
        'lng: ' + Math.round(event.latLng.lng());
  });

  // Add some markers to the map.
  map.data.setStyle(function(feature) {
    return {
      title: feature.getProperty('name'),
      optimized: false
    };
  });
  map.data.addGeoJson(cities);
}

var gallPetersMapType;
function initGallPeters() {
  var GALL_PETERS_RANGE_X = 800;
  var GALL_PETERS_RANGE_Y = 512;

  // Fetch Gall-Peters tiles stored locally on our server.
  gallPetersMapType = new google.maps.ImageMapType({
    getTileUrl: function(coord, zoom) {
      var scale = 1 << zoom;

      // Wrap tiles horizontally.
      var x = ((coord.x % scale) + scale) % scale;

      // Don't wrap tiles vertically.
      var y = coord.y;
      if (y < 0 || y >= scale) return null;

      return 'https://developers.google.com/maps/documentation/' +
             'javascript/examples/full/images/gall-peters_' + zoom +
             '_' + x + '_' + y + '.png';
    },
    tileSize: new google.maps.Size(GALL_PETERS_RANGE_X, GALL_PETERS_RANGE_Y),
    isPng: true,
    minZoom: 0,
    maxZoom: 1,
    name: 'Gall-Peters'
  });

  // Describe the Gall-Peters projection used by these tiles.
  gallPetersMapType.projection = {
    fromLatLngToPoint: function(latLng) {
      var latRadians = latLng.lat() * Math.PI / 180;
      return new google.maps.Point(
          GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360),
          GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians)));
    },
    fromPointToLatLng: function(point, noWrap) {
      var x = point.x / GALL_PETERS_RANGE_X;
      var y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y));

      return new google.maps.LatLng(
          Math.asin(1 - 2 * y) * 180 / Math.PI,
          -180 + 360 * x,
          noWrap);
    }
  };
}

// GeoJSON, describing the locations and names of some cities.
var cities = {
  type: 'FeatureCollection',
  features: [{
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [-87.650, 41.850]},
    properties: {name: 'Chicago'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [-149.900, 61.218]},
    properties: {name: 'Anchorage'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [-99.127, 19.427]},
    properties: {name: 'Mexico City'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [-0.126, 51.500]},
    properties: {name: 'London'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [28.045, -26.201]},
    properties: {name: 'Johannesburg'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [15.322, -4.325]},
    properties: {name: 'Kinshasa'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [151.207, -33.867]},
    properties: {name: 'Sydney'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [0, 0]},
    properties: {name: '0°N 0°E'}
  }]
};
<div id="map"></div>
<div id="coords"></div>
#coords {
  background-color: black;
  color: white;
  padding: 5px;
}
<!-- Replace the value of the key parameter with your own API key. -->
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap"></script>
// This example defines an image map type using the Gall-Peters
// projection.
// https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection

function initMap() {
  // Create a map. Use the Gall-Peters map type.
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 0,
    center: {lat: 0, lng: 0},
    mapTypeControl: false
  });

  initGallPeters();
  map.mapTypes.set('gallPeters', gallPetersMapType);
  map.setMapTypeId('gallPeters');

  // Show the lat and lng under the mouse cursor.
  var coordsDiv = document.getElementById('coords');
  map.controls[google.maps.ControlPosition.TOP_CENTER].push(coordsDiv);
  map.addListener('mousemove', function(event) {
    coordsDiv.textContent =
        'lat: ' + Math.round(event.latLng.lat()) + ', ' +
        'lng: ' + Math.round(event.latLng.lng());
  });

  // Add some markers to the map.
  map.data.setStyle(function(feature) {
    return {
      title: feature.getProperty('name'),
      optimized: false
    };
  });
  map.data.addGeoJson(cities);
}

var gallPetersMapType;
function initGallPeters() {
  var GALL_PETERS_RANGE_X = 800;
  var GALL_PETERS_RANGE_Y = 512;

  // Fetch Gall-Peters tiles stored locally on our server.
  gallPetersMapType = new google.maps.ImageMapType({
    getTileUrl: function(coord, zoom) {
      var scale = 1 << zoom;

      // Wrap tiles horizontally.
      var x = ((coord.x % scale) + scale) % scale;

      // Don't wrap tiles vertically.
      var y = coord.y;
      if (y < 0 || y >= scale) return null;

      return 'https://developers.google.com/maps/documentation/' +
             'javascript/examples/full/images/gall-peters_' + zoom +
             '_' + x + '_' + y + '.png';
    },
    tileSize: new google.maps.Size(GALL_PETERS_RANGE_X, GALL_PETERS_RANGE_Y),
    isPng: true,
    minZoom: 0,
    maxZoom: 1,
    name: 'Gall-Peters'
  });

  // Describe the Gall-Peters projection used by these tiles.
  gallPetersMapType.projection = {
    fromLatLngToPoint: function(latLng) {
      var latRadians = latLng.lat() * Math.PI / 180;
      return new google.maps.Point(
          GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360),
          GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians)));
    },
    fromPointToLatLng: function(point, noWrap) {
      var x = point.x / GALL_PETERS_RANGE_X;
      var y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y));

      return new google.maps.LatLng(
          Math.asin(1 - 2 * y) * 180 / Math.PI,
          -180 + 360 * x,
          noWrap);
    }
  };
}

// GeoJSON, describing the locations and names of some cities.
var cities = {
  type: 'FeatureCollection',
  features: [{
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [-87.650, 41.850]},
    properties: {name: 'Chicago'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [-149.900, 61.218]},
    properties: {name: 'Anchorage'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [-99.127, 19.427]},
    properties: {name: 'Mexico City'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [-0.126, 51.500]},
    properties: {name: 'London'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [28.045, -26.201]},
    properties: {name: 'Johannesburg'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [15.322, -4.325]},
    properties: {name: 'Kinshasa'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [151.207, -33.867]},
    properties: {name: 'Sydney'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [0, 0]},
    properties: {name: '0°N 0°E'}
  }]
};

Просмотр примера (map-projection-simple.html).

Оставить отзыв о...

Текущей странице
Google Maps JavaScript API
Google Maps JavaScript API
Нужна помощь? Обратитесь в службу поддержки.