Камера и область просмотра

Выберите платформу: Android iOS JavaScript

Карты, загруженные через Maps SDK для Android, можно наклонять и поворачивать с помощью жестов – так, как удобно пользователю. Задержка при этом очень невелика на любом уровне масштабирования, поскольку у векторной базовой карты фрагменты занимают меньше места в памяти устройства, чем у растровой.

Примеры кода

В репозитории ApiDemos на сайте GitHub доступен пример, где демонстрируется использование функций камеры.

Введение

Как и в веб-приложении "Google Карты", в Maps SDK для Android используется проекция Меркатора. При перемещении на восток или запад карта не прерывается – как при вращении глобуса вправо или влево. В северном и южном направлениях она заканчивается в районе 85-го градуса соответствующей широты.

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

Maps SDK для Android позволяет изменять пользовательскую точку обзора, изменяя положение камеры для карты.

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

Жесты пользователя отслеживаются с помощью прослушивателей. Например, метод обратного вызова OnMapClickListener.onMapClick() реагирует на одно нажатие на карте. Так как методу передаются значения широты и долготы точки нажатия, вы можете определить такое поведение, при котором ответом на нажатие будет увеличение масштаба или центрирование карты относительно этой точки. Похожие методы также используются для обработки нажатий на всплывающие окна или жестов перетаскивания маркеров.

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

Положение камеры

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

Схема свойств карты

Цель камеры (местоположение)

Цель камеры – это местоположение, которое должно быть в центре карты. Оно задается широтой и долготой.

Широта может принимать значение от -85 до 85 градусов включительно. Значения, лежащие за пределами этого диапазона, отсекаются до ближайших граничных. Например, если для широты указано число 100, то это значение будет уменьшено до 85. Долгота может принимать значение от -180 до 180 градусов включительно. Значения, которые находятся вне указанного диапазона, пересчитываются так, чтобы уместиться в него (-180, 180). Например, 480, 840 и 1200 градусов после пересчета будут равны 120 градусам.

Азимут (ориентация)

Азимут камеры указывается как направление по компасу, измеряемое в градусах отклонения от географического севера, который соответствует верхнему краю карты. Если нарисовать вертикальную линию от центра карты до ее верхнего края, азимут соответствует отклонению камеры в градусах от этой линии.

Нулевой азимут означает, что верхний край карты соответствует географическому северу. Значение 90 означает, что верхний край карты соответствует востоку (90 градусов на компасе), а 180 – югу.

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

Наклон (угол обзора)

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

На рисунках ниже угол обзора составляет 0 градусов. На рисунке справа наклон представлен схематически: 1 – это положение камеры, а 2 – положение карты. Полученная карта показана ниже.

Скриншот карты с углом обзора 0 градусов и уровнем масштабирования 18
Вид карты под углом обзора по умолчанию
Схема, показывающая положение камеры по умолчанию (с углом наклона 0°).
Угол наклона камеры по умолчанию

На приведенных ниже рисунках угол обзора равен 45 градусам. Обратите внимание, что камера смещается в центр дуги, соединяющей точку зенита (0 градусов) с земной поверхностью (90 градусов). Положение камеры обозначено цифрой 3. Она по-прежнему направлена в центр карты, но теперь пользователю также становится видна область 4.

Скриншот карты с углом обзора 45 градусов и уровнем масштабирования 18
Вид карты с углом обзора 45 градусов
Схема, показывающая положение камеры под углом 45 градусов с уровнем масштабирования 18
Угол наклона камеры – 45 градусов

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

Масштаб

Уровень масштабирования камеры определяет масштаб карты. Чем он выше, тем больше деталей можно рассмотреть, зато при уменьшении масштаба на экране умещается большая территория. При уровне масштабирования 0 вся карта мира имеет ширину около 256 dp (пикселей, не зависящих от плотности экрана).

Увеличение уровня масштабирования на единицу удваивает ширину карты на экране. Таким образом, на уровне N она составляет 256*2N dp. Например, на уровне масштабирования 2 ширина карты составляет приблизительно 1024 dp.

Значение уровня масштабирования может быть не целым числом. Диапазон допустимых значений зависит от ряда критериев, таких как тип карты, целевое местоположение и размер экрана. Число за пределами этого диапазона преобразуется в ближайшее допустимое значение, то есть минимальное или максимальное значение уровня масштабирования. В списке ниже показан примерный уровень детализации, который можно ожидать на каждом уровне масштабирования:

  • 1: мир;
  • 5: континент;
  • 10: город;
  • 15: улицы;
  • 20: здания.
На следующих изображениях представлены различные уровни масштабирования:
Скриншот карты с уровнем масштабирования 5
Карта с уровнем масштабирования 5
Скриншот карты с уровнем масштабирования 15
Карта с уровнем масштабирования 15
Скриншот карты с уровнем масштабирования 20
Карта с уровнем масштабирования 20

Перемещение камеры

Maps API позволяет выбирать, какая часть мира будет видна на карте, за счет изменения положения камеры (не путайте со смещением карты).

Перемещения камеры можно анимировать, при этом значения текущих и измененных атрибутов камеры интерполируются. Длительность анимации также можно настроить.

Чтобы изменить положение камеры, укажите, куда нужно ее передвинуть, с помощью объекта CameraUpdate. Maps API позволяет создать много разных типов CameraUpdate с помощью CameraUpdateFactory. Доступны описанные ниже параметры.

Изменение уровня масштабирования и назначение максимального и минимального уровней масштабирования

Методы CameraUpdateFactory.zoomIn() и CameraUpdateFactory.zoomOut() позволяют получить объект CameraUpdate, изменяющий уровень масштабирования на 1,0 и оставляющий все остальные свойства без изменений.

Метод CameraUpdateFactory.zoomTo(float) возвращает объект CameraUpdate, задающий уровень масштабирования, равный указанной величине, и оставляющий все остальные свойства без изменений.

Методы CameraUpdateFactory.zoomBy(float) и CameraUpdateFactory.zoomBy(float, Point) возвращают объект CameraUpdate, повышающий уровень масштабирования на указанное значение (или понижающий, если значение отрицательное). Второй метод закрепляет заданную точку на экране, чтобы широта и долгота остались прежними, поэтому в результате его вызова положение камеры может измениться.

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

Kotlin



private lateinit var map: GoogleMap

    map.setMinZoomPreference(6.0f)
    map.setMaxZoomPreference(14.0f)

      

Java


private GoogleMap map;
    map.setMinZoomPreference(6.0f);
    map.setMaxZoomPreference(14.0f);

      

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

Изменение положения камеры

Существуют два распространенных метода, позволяющих менять положение камеры. Метод CameraUpdateFactory.newLatLng(LatLng) возвращает объект CameraUpdate, изменяющий широту и долготу, оставляя все прочие свойства прежними. Метод CameraUpdateFactory.newLatLngZoom(LatLng, float) возвращает объект CameraUpdate, изменяющий широту, долготу и уровень масштабирования, оставляя все прочие свойства прежними.

Если вам нужны более широкие возможности для управления положением камеры, используйте метод CameraUpdateFactory.newCameraPosition(CameraPosition). Он возвращает объект CameraUpdate, передвигающий камеру в указанное положение. Объект CameraPosition можно получить либо напрямую с помощью метода new CameraPosition(), либо через объект CameraPosition.Builder с помощью метода new CameraPosition.Builder().

Панорамирование (прокрутка)

Метод CameraUpdateFactory.scrollBy(float, float) возвращает объект CameraUpdate, изменяющий широту и долготу положения камеры так, что камера передвигается на указанное количество пикселей. При положительном значении X камера смещается вправо (т. е. карта смещается влево). При положительном значении Y камера смещается вниз (т. е. карта смещается вверх). Отрицательные значения X и Y смещают камеру соответственно влево и вверх (а карта смещается вправо и вниз). Панорамирование выполняется с учетом текущей ориентации камеры (например, если угол ориентации – 90 градусов, то восток находится вверху).

Установка границ

Установка границ карты

Иногда требуется сместить камеру так, чтобы интересующая область показывалась с максимальным приближением. Например, если вы хотите показать все заправочные станции в радиусе 5 км от пользователя, нужно выбрать для камеры такое положение, из которого все они будут видны. Для этого сначала нужно вычислить границы LatLngBounds для области, которую вы хотите отобразить на экране. Затем с помощью метода CameraUpdateFactory.newLatLngBounds(LatLngBounds bounds, int padding) можно получить объект CameraUpdate, изменяющий положение камеры так, чтобы указанная область LatLngBounds полностью помещалась на карте с учетом заданных отступов по краям карты (в пикселях). Возвращаемый объект CameraUpdate генерируется так, чтобы расстояние в пикселях между границей области и краем карты было не меньше ширины заданного отступа. Обратите внимание, что значения наклона и азимута будут равны нулю.

Kotlin



val australiaBounds = LatLngBounds(
    LatLng((-44.0), 113.0),  // SW bounds
    LatLng((-10.0), 154.0) // NE bounds
)
map.moveCamera(CameraUpdateFactory.newLatLngBounds(australiaBounds, 0))

      

Java


LatLngBounds australiaBounds = new LatLngBounds(
    new LatLng(-44, 113), // SW bounds
    new LatLng(-10, 154)  // NE bounds
);
map.moveCamera(CameraUpdateFactory.newLatLngBounds(australiaBounds, 0));

      

Выравнивание карты по центру заданной области

Иногда требуется поместить камеру в центр определенной области, не задавая жестких границ, например чтобы отобразить страну при сохранении текущего масштаба. Для этого можно создать объект LatLngBounds и вызвать метод CameraUpdateFactory.newLatLngZoom(LatLng latLng, float zoom), используя возвращаемое значение метода LatLngBounds.Метод getCenter(): указывает географический центр области, определенной объектом LatLngBounds.

Kotlin



val australiaBounds = LatLngBounds(
    LatLng((-44.0), 113.0),  // SW bounds
    LatLng((-10.0), 154.0) // NE bounds
)
map.moveCamera(CameraUpdateFactory.newLatLngZoom(australiaBounds.center, 10f))

      

Java


LatLngBounds australiaBounds = new LatLngBounds(
    new LatLng(-44, 113), // SW bounds
    new LatLng(-10, 154)  // NE bounds
);
map.moveCamera(CameraUpdateFactory.newLatLngZoom(australiaBounds.getCenter(), 10));

      

За счет перегрузки метода newLatLngBounds(boundary, width, height, padding) можно задать ширину и высоту прямоугольника в пикселях, исходя из размеров карты. Прямоугольник будет размещен так, чтобы его центр совпадал с центром отображаемой области карты. Таким образом, если его размеры равны размерам отображаемой области карты, он будет полностью с ней совпадать. Возвращаемый объект CameraUpdate сместит камеру так, чтобы область LatLngBounds выравнивалась по центру заданного прямоугольника с максимально возможным уровнем масштабирования (с учетом отступов по краям).

Примечание. Простой метод newLatLngBounds(boundary, padding) подойдет для создания объекта CameraUpdate только в том случае, если этот объект будет использоваться для перемещения камеры после того, как будет готов макет карты. API при создании макета вычисляет границы отображаемой области карты, чтобы правильно определить граничные рамки. Объект CameraUpdate, возвращаемый сложным методом newLatLngBounds(boundary, width, height, padding), можно использовать в любой момент, даже до готовности макета карты. Это объясняется тем, что API вычисляет границы отображаемой области на основании аргументов, переданных методу.

Ограничение области, в которой пользователь может сдвигать карту

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

Kotlin



// Create a LatLngBounds that includes the city of Adelaide in Australia.
val adelaideBounds = LatLngBounds(
    LatLng(-35.0, 138.58),  // SW bounds
    LatLng(-34.9, 138.61) // NE bounds
)

// Constrain the camera target to the Adelaide bounds.
map.setLatLngBoundsForCameraTarget(adelaideBounds)

      

Java


// Create a LatLngBounds that includes the city of Adelaide in Australia.
LatLngBounds adelaideBounds = new LatLngBounds(
    new LatLng(-35.0, 138.58), // SW bounds
    new LatLng(-34.9, 138.61)  // NE bounds
);

// Constrain the camera target to the Adelaide bounds.
map.setLatLngBoundsForCameraTarget(adelaideBounds);

      

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

Схема сценария, где область LatLngBounds больше области просмотра.

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

Схема, на которой цель камеры находится в правом нижнем углу области LatLngBounds.

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

Схема сценария, где область LatLngBounds меньше области просмотра.

Обновление области просмотра

При применении параметров объекта CameraUpdate можно переместить камеру в новое положение моментально или плавно. Чтобы моментально переместить камеру с помощью объекта CameraUpdate, используйте метод GoogleMap.moveCamera(CameraUpdate).

Плавное перемещение выглядит лучше, особенно если расстояние невелико. Чтобы переместить камеру плавно, вместо метода GoogleMap.moveCamera вызовите метод GoogleMap.animateCamera. Карта плавно займет новую позицию согласно указанным атрибутам. Наиболее подробный вариант этого метода – GoogleMap.animateCamera(cameraUpdate, duration, callback) – принимает три аргумента, которые описаны ниже.

cameraUpdate
Объект CameraUpdate, указывающий, куда перемещать камеру.
callback
Объект, реализующий GoogleMap.CancellableCallback. Этот обобщенный интерфейс для обработки заданий определяет два метода: onCancel() и onFinished(). Для целей анимации они вызываются в следующих случаях:
onFinish()
Вызывается, если анимация выполняется непрерывно.
onCancel()

Вызывается, если анимация прерывается в результате вызова метода stopAnimation() или из-за начала нового движения камеры.

Это также может произойти при вызове метода GoogleMap.stopAnimation().

duration
Целое число (int), указывающее длительность анимации в миллисекундах.

В приведенных ниже фрагментах кода показаны некоторые типичные способы перемещения камеры.

Kotlin



val sydney = LatLng(-33.88, 151.21)
val mountainView = LatLng(37.4, -122.1)

// Move the camera instantly to Sydney with a zoom of 15.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 15f))

// Zoom in, animating the camera.
map.animateCamera(CameraUpdateFactory.zoomIn())

// Zoom out to zoom level 10, animating with a duration of 2 seconds.
map.animateCamera(CameraUpdateFactory.zoomTo(10f), 2000, null)

// Construct a CameraPosition focusing on Mountain View and animate the camera to that position.
val cameraPosition = CameraPosition.Builder()
    .target(mountainView) // Sets the center of the map to Mountain View
    .zoom(17f)            // Sets the zoom
    .bearing(90f)         // Sets the orientation of the camera to east
    .tilt(30f)            // Sets the tilt of the camera to 30 degrees
    .build()              // Creates a CameraPosition from the builder
map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition))

      

Java


LatLng sydney = new LatLng(-33.88,151.21);
LatLng mountainView = new LatLng(37.4, -122.1);

// Move the camera instantly to Sydney with a zoom of 15.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 15));

// Zoom in, animating the camera.
map.animateCamera(CameraUpdateFactory.zoomIn());

// Zoom out to zoom level 10, animating with a duration of 2 seconds.
map.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);

// Construct a CameraPosition focusing on Mountain View and animate the camera to that position.
CameraPosition cameraPosition = new CameraPosition.Builder()
    .target(mountainView )      // Sets the center of the map to Mountain View
    .zoom(17)                   // Sets the zoom
    .bearing(90)                // Sets the orientation of the camera to east
    .tilt(30)                   // Sets the tilt of the camera to 30 degrees
    .build();                   // Creates a CameraPosition from the builder
map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));