Пользовательские контролы (Custom Controls) в Google Maps JavaScript API позволяют добавлять на карту собственные элементы управления, полностью адаптированные под требования приложения. В отличие от стандартных элементов интерфейса, таких как кнопки масштабирования, переключатель типа карты или полноэкранный режим, пользовательские контролы могут выполнять любые действия:
Контрол представляет собой обычный HTML-элемент, который размещается внутри контейнера карты через специальный механизм API.
Каждая карта содержит набор позиций, в которых могут располагаться
элементы управления. Для управления используется коллекция
controls.
Добавление элемента выполняется через массив соответствующей позиции:
map.controls[google.maps.ControlPosition.TOP_CENTER].push(controlDiv);
Где:
map.controls — коллекция всех контролов;ControlPosition — место размещения;controlDiv — HTML-элемент.Схематически процесс выглядит следующим образом:
Google Maps предоставляет множество предопределённых областей размещения.
google.maps.ControlPosition.TOP_LEFT
google.maps.ControlPosition.TOP_CENTER
google.maps.ControlPosition.TOP_RIGHT
google.maps.ControlPosition.LEFT_TOP
google.maps.ControlPosition.LEFT_CENTER
google.maps.ControlPosition.LEFT_BOTTOM
google.maps.ControlPosition.RIGHT_TOP
google.maps.ControlPosition.RIGHT_CENTER
google.maps.ControlPosition.RIGHT_BOTTOM
google.maps.ControlPosition.BOTTOM_LEFT
google.maps.ControlPosition.BOTTOM_CENTER
google.maps.ControlPosition.BOTTOM_RIGHT
Наиболее часто используются:
| Позиция | Описание |
|---|---|
| TOP_LEFT | Верхний левый угол |
| TOP_RIGHT | Верхний правый угол |
| TOP_CENTER | Верхняя центральная область |
| BOTTOM_LEFT | Нижний левый угол |
| BOTTOM_RIGHT | Нижний правый угол |
Выбор позиции зависит от структуры интерфейса и наличия стандартных контролов.
Простейший контрол представляет собой кнопку.
function createControl(map) {
const button = document.createElement("button");
button.textContent = "Перейти в Москву";
button.style.background = "#fff";
button.style.border = "2px solid #fff";
button.style.borderRadius = "3px";
button.style.padding = "8px 16px";
button.style.cursor = "pointer";
button.addEventListener("click", () => {
map.setCenter({
lat: 55.7558,
lng: 37.6176
});
map.setZoom(12);
});
map.controls[
google.maps.ControlPosition.TOP_CENTER
].push(button);
}
После нажатия карта перемещается в Москву и устанавливает новый уровень масштабирования.
const map = new google.maps.Map(
document.getElementById("map"),
{
center: {
lat: 51.1694,
lng: 71.4491
},
zoom: 6
}
);
const controlDiv = document.createElement("div");
const button = document.createElement("button");
button.textContent = "Домой";
button.style.backgroundColor = "#ffffff";
button.style.border = "none";
button.style.padding = "10px 15px";
button.style.margin = "10px";
button.style.borderRadius = "4px";
button.style.boxShadow =
"0 2px 6px rgba(0,0,0,0.3)";
button.style.cursor = "pointer";
button.addEventListener("click", () => {
map.panTo({
lat: 51.1694,
lng: 71.4491
});
});
controlDiv.appendChild(button);
map.controls[
google.maps.ControlPosition.TOP_LEFT
].push(controlDiv);
В крупных проектах логика контролов часто оформляется в виде классов.
class HomeControl {
constructor(map) {
this.map = map;
this.element =
document.createElement("button");
this.initialize();
}
initialize() {
this.element.textContent = "Домой";
this.element.addEventListener(
"click",
() => {
this.map.setCenter({
lat: 51.1694,
lng: 71.4491
});
}
);
}
}
Подключение:
const control = new HomeControl(map);
map.controls[
google.maps.ControlPosition.TOP_LEFT
].push(control.element);
Такой подход облегчает поддержку кода и повторное использование компонентов.
Контрол может изменять тип отображения карты.
const button = document.createElement("button");
button.textContent = "Спутник";
button.addEventListener("click", () => {
map.setMapTypeId("satellite");
});
Переключение обратно:
button.addEventListener("dblclick", () => {
map.setMapTypeId("roadmap");
});
Возможные типы:
roadmap
satellite
hybrid
terrain
Пример переключателя:
let satellite = false;
button.addEventListener("click", () => {
satellite = !satellite;
map.setMapTypeId(
satellite
? "satellite"
: "roadmap"
);
});
Пользовательские кнопки могут заменять стандартный Zoom Control.
zoomInButton.addEventListener(
"click",
() => {
map.setZoom(
map.getZoom() + 1
);
}
);
zoomOutButton.addEventListener(
"click",
() => {
map.setZoom(
map.getZoom() - 1
);
}
);
Отключение стандартного контрола:
const map = new google.maps.Map(
document.getElementById("map"),
{
zoomControl: false
}
);
Очень распространённый вариант пользовательского управления.
button.addEventListener("click", () => {
navigator.geolocation.getCurrentPosition(
(position) => {
const location = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
map.setCenter(location);
new google.maps.Marker({
position: location,
map
});
}
);
});
После нажатия карта автоматически перемещается к текущим координатам пользователя.
Часто требуется скрывать или отображать группы маркеров.
const markers = [];
Скрытие:
button.addEventListener("click", () => {
markers.forEach(marker => {
marker.setMap(null);
});
});
Отображение:
button.addEventListener("click", () => {
markers.forEach(marker => {
marker.setMap(map);
});
});
Переключение:
let visible = true;
button.addEventListener("click", () => {
visible = !visible;
markers.forEach(marker => {
marker.setMap(
visible ? map : null
);
});
});
Контрол не обязан состоять из одной кнопки.
Внутри контейнера можно разместить полноценную панель.
const panel =
document.createElement("div");
Добавление кнопок:
panel.appendChild(zoomInButton);
panel.appendChild(zoomOutButton);
panel.appendChild(homeButton);
panel.appendChild(searchButton);
Размещение:
map.controls[
google.maps.ControlPosition.RIGHT_TOP
].push(panel);
Так создаются компактные панели управления картой.
Вместо инлайн-стилей рекомендуется использовать CSS.
.map-control {
background: white;
border-radius: 4px;
padding: 10px;
margin: 10px;
cursor: pointer;
box-shadow:
0 2px 6px rgba(0,0,0,.3);
}
Создание элемента:
const button =
document.createElement("button");
button.classList.add("map-control");
Преимущества:
Контрол может реагировать на изменение состояния карты.
Например, отображать текущий масштаб.
const info =
document.createElement("div");
Обновление значения:
map.addListener("zoom_changed", () => {
info.textContent =
`Zoom: ${map.getZoom()}`;
});
Таким образом контрол становится динамическим элементом интерфейса.
Пример отображения координат центра карты.
const info =
document.createElement("div");
Обновление данных:
function updateInfo() {
const center =
map.getCenter();
info.innerHTML = `
Lat:
${center.lat().toFixed(5)}
<br>
Lng:
${center.lng().toFixed(5)}
`;
}
Подписка на события:
map.addListener(
"center_changed",
updateInfo
);
Первичная инициализация:
updateInfo();
Контрол будет автоматически обновляться при перемещении карты.
Для удаления можно использовать DOM-операции.
button.remove();
Или удалить родительский контейнер:
controlDiv.remove();
Если требуется временно скрыть элемент:
controlDiv.style.display = "none";
Повторное отображение:
controlDiv.style.display = "block";
При разработке интерфейсов с большим количеством элементов рекомендуется:
Неэффективный вариант:
map.addListener(
"bounds_changed",
() => {
expensiveCalculation();
}
);
Более корректный вариант:
const update =
debounce(expensiveCalculation, 300);
map.addListener(
"bounds_changed",
update
);
Пользовательские контролы могут работать одновременно со встроенными элементами интерфейса.
Настройка карты:
const map = new google.maps.Map(
document.getElementById("map"),
{
zoomControl: true,
mapTypeControl: true,
streetViewControl: true,
fullscreenControl: true
}
);
Добавление собственного контрола:
map.controls[
google.maps.ControlPosition.TOP_RIGHT
].push(customControl);
Такой подход позволяет сохранить привычный интерфейс Google Maps и дополнить его специализированными возможностями приложения.
В масштабных приложениях пользовательские контролы обычно организуются как независимые компоненты.
Пример структуры:
controls/
│
├── HomeControl.js
├── SearchControl.js
├── FilterControl.js
├── LayerControl.js
└── ZoomControl.js
Каждый компонент отвечает только за одну задачу:
Подобная организация упрощает тестирование, поддержку и расширение функциональности картографического приложения на базе Google Maps JavaScript API.