image

→ Демо: ссылка
→ Исходники: ссылка

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

В этой статье мы рассмотрим:

1. Внедрение Google Maps на сайт

  • Добавление через вставку iframe в разметку
  • Добавление через API

2. Кастомизация маркера

  • Инициализация маркера
  • Анимация маркера
  • Изображение маркера

3. Кастомизация информационного окна

  • Добавление информационного окна
  • Открытие информационного окна
  • Кастомизация элементов информационного окна
  • Параллакс-эффект для элементов в информационном окне

4. Кастомизация карты

  • Изменение цвета объектов карты
  • Кастомизация элементов управления
  • Маска для карты

1. Внедрение на сайт

Добавление через вставку iframe в разметку

Если у вас нет необходимости изменять маркер, делать кастомное информационное окно или еще каким-либо образом воздействовать на карту, для ее добавления достаточно сделать следующее:

  • Открыть Google Maps.
  • Найти интересующий объект (например, введя адрес в поиске, либо нажав на нужное название правой кнопкой мыши и выбрав пункт в контекстном меню «Что здесь?»)

    image

    после чего кликнуть на гамбургер:

    image

    Затем находим кнопку «Ссылка/код»:

    image

    Копируем код для вставки:

    image

    Осталось только вставить полученный код в разметку.

Добавление через API

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

Встраиваем его в адрес вместо YOUR_API_KEY:

<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>

Если нужно вызывать коллбэк после загрузки api, после ключа надо будет дописать YOUR_API_KEY&callback=initMap с названием вашей функции. Подключаем скрипт на странице и создаем в разметке блок для будущей карты:

<div id="map"></div>

Теперь необходимо инициализировать карту:

function initMap() {
    var coordinates = {lat: 47.212325, lng: 38.933663},
    
        map = new google.maps.Map(document.getElementById('map'), {
            center: coordinates
        });
}

Координаты можно узнать при помощи опции «Что здесь», описанной выше.

Свойства, которые могут сразу понадобиться:

  • zoom: number — определяет первоначальный масштаб.
  • disableDefaultUI: boolean – убирает элементы управления.
  • scrollwheel: boolean — отключает масштабирование колесиком мыши (бывает полезно, если карта на всю ширину страницы и перебивает прокрутку вниз).

2. Кастомизация маркера

Инициализация маркера

Для начала добавим маркер:

function initMap() {
    var coordinates = {lat: 47.212325, lng: 38.933663},

        map = new google.maps.Map(document.getElementById('map'), {
            center: coordinates
        }),
    
        marker = new google.maps.Marker({
            position: coordinates,
            map: map
        });
}

position (обязательно) указывает начальное положение маркера. Если указать те же координаты, что и для карты, то маркер будет по центру экрана. Сместить маркер можно изменив значение координат, либо сменив положение самой карты относительно видимой области (родительского блока).
map (не обязательно) указывает карту, н�� которой помещается маркер.

Анимация маркера

Для маркера можно задать анимацию:

  • DROP – после загрузки карты маркер падает сверху.
  • BOUNCE – маркер подпрыгивает на месте.

function initMap() {
    var coordinates = {lat: 47.212325, lng: 38.933663},

        map = new google.maps.Map(document.getElementById('map'), {
            center: coordinates
        }),

        marker = new google.maps.Marker({
            position: coordinates,
            map: map,
            animation: google.maps.Animation.BOUNCE
        });
}

Анимацию можно задать при инициализации маркера, добавить или убрать, вызвав метод setAnimation().

Пример анимации маркера при закрытии информационного окна и прекращении при открытии:

google.maps.event.addListener(infowindow,'closeclick',function(){
    marker.setAnimation(google.maps.Animation.BOUNCE);
});

marker.addListener('click', function () {
    marker.setAnimation(null);
});

Изображение маркера

Изображение маркера можно изменить, задав адрес картинки для свойства icon.

image = 'images/marker.png',
marker = new google.maps.Marker({
    position: coordinates,
    map: map,
    icon: image
});

3. Кастомизация информационного окна

Добавление информационного окна

В кастомное информационное окно можно добавить любую разметку через свойство content:

function initMap() {
    var coordinates = {lat: 47.212325, lng: 38.933663},
        popupContent = '<p class="content">Что угодно</p>',
        markerImage = 'images/marker.png',

        map = new google.maps.Map(document.getElementById('map'), {
            center: {lat: 47.212325, lng: 38.933663}
        }),

        marker = new google.maps.Marker({
            position: coordinates,
            map: map,
            icon: markerImage
        }),

        infowindow = new google.maps.InfoWindow({
            content: popupContent
        });
}

Открытие информационного окна

Чтобы информационное окно было видно сразу, надо вызвать метод open():

infowindow.open(map, marker);

Также следует добавить вызов окна при клике на маркер (в противном случае мы не сможем открыть попап):

marker.addListener('click', function() {
    infowindow.open(map, marker);
});

Кастомизация элементов информационного окна

Информационное окно может быть как кастомное, так и стандартное. В кастомное мы можем добавить любые элементы и работать с ними, возможности ограничены лишь фантазией.

Основная проблема, с которой можно столкнуться при кастомизации любого из типов – края (белая область) вокруг контента и стрелочка. Эти элементы не поддаются css выборке.

image

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

.gm-style-iw {
  background: $black;
  box-shadow: -14px 0px 0px $black, -14px 9px 0px $black, -14px -8px 0px $black, 15px -8px 0px $black, 15px 9px 0px $black;
}

Но обо всем по порядку:

.gm-style-iw — основной блок, в нем находится контент. На скриншоте, расположенном выше, этот блок имеет черный фон.
.poi-info-window — обертка для текста в стандартном информационном окне, находится внутри. .gm-style-iw
.gm-style-iw + div – крестик.

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

.gm-style-iw {
  overflow: visible !important;

  div {
    overflow: visible !important;
  }
}

Теперь для .gm-style-iw, или блоков внутри можно создать псевдоэлементы для перекрытия фона и стрелочки:

.gm-style-iw {
  // Фон
  &::before {
    content: '';
    width: calc(100% + 29px);
    height: calc(100% + 17px);
    @include absolute;
    @include center-align;
    background: $black;
  }
  
  // Стрелочка
  &::after {
    content: '';
    width: 0;
    height: 0;
    border: 22px solid transparent;
    border-top-color: $black;
    z-index: 4;
    @include absolute;
    top: auto;
    bottom: -53px;
    margin: auto;
  }
}

Получаем следующее:

image

Параллакс-эффект для элементов в информационном окне

Тут возникает небольшая проблема, связанная с тем, что объекты карты создаются динамически, и нельзя просто так взять и прикрепить к ним обработчик, а клонировать блок при помощи .clone(true) в контент информационного окна с переносом обработчиков нам не позволит API.

Как вариант, можно проверять наличие элемента и сохранять после появления:

var $parallaxImg  = null;
this.$body.mousemove(function(e) {
    if($parallaxImg) {
        ...
    } else if($(this.parallaxImg).length) {
        $parallaxImg = $(this.parallaxImg);
    }
}.bind(this));

Теперь просто добавим код, смещающий блок по горизонтали в зависимости от положения курсора:

var $parallaxImg  = null;

this.$body.mousemove(function(e) {
    if($parallaxImg) {
        var $el    = $(e.currentTarget),
            xPos   = e.pageX - (window.innerWidth / 2),
            mXPcnt = Math.round(xPos / $el.width() * 100),
            diffX  = $parallaxImg.width() - $el.width(),
            myX    = diffX * (mXPcnt / 1500);

        $parallaxImg.animate({left: myX}, 0);
    } else if($(this.parallaxImg).length) {
        $parallaxImg = $(this.parallaxImg);
    }
}.bind(this));

Если клик по динамическому элементу нужно обработать, просто ставим обработчик на обертку и ловим объект на всплытии:

$('.map').on('click', '.js-parallax-img', function() {
    ...
});

4. Кастомизация карты

Изменение цвета объектов карты

Для стилизации карты используется массив стилей, в котором указывается селектор и css-свойство, которое необходимо применить.

Пример настроек, окрашивающих воду в фиолетовый цвет:

var styles = [
        {
            "featureType": "water",
            "stylers": [
                {
                    "color": "#a73cff"
                }
            ]
        }
    ]

Применяем параметры:

map.setOptions({styles: styles});

Для настройки стилей проще всего использовать специализированный сервис, к примеру Google Maps APIs Styling Wizard. Для детальной настройки карты жмем «More options»:

image

Производим настройку:

image

Копируем полученный json:

image

Если массив стилей очень большой, его можно поместить в отдельный .json файл и применить стили после его загрузки:

$.getJSON("../json/map-style/map-style.json", function(data) {
    map.setOptions({styles: data});
});

В конечном итоге получаем вот такие настройки карты:

var coordinates = {lat: 47.212325, lng: 38.933663},
    popupContent = this.$popupContent.html(),
    markerImage = 'images/marker.png',
    zoom = 15,

    map = new google.maps.Map(document.getElementById('map'), {
        center: coordinates,
        zoom: zoom,
        disableDefaultUI: true
    }),

    infowindow = new google.maps.InfoWindow({
        content: popupContent
    }),

    marker = new google.maps.Marker({
        position: coordinates,
        map: map,
        icon: markerImage
    });

$.getJSON("../json/map-style/map-style_colored.json", function(data) {
    map.setOptions({styles: data});
});

google.maps.event.addListener(infowindow,'closeclick',function(){
    marker.setAnimation(google.maps.Animation.BOUNCE);
});

marker.addListener('click', function () {
    marker.setAnimation(null);
});

marker.addListener('click', function() {
    infowindow.open(map, marker);
});

infowindow.open(map, marker);

Кастомизация элементов управления

image

Кнопки «Карта» и «Спутник» находятся в блоке с классом .gm-style-mtc

image

Кнопки увеличения и уменьшения изображения в блоке с классом .gmnoprint

image

Кнопка режима просмотра улиц имеет класс .gm-svpc

image

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

.gm-style-mtc > div,
.gmnoprint > div,
.gm-svpc {
  background-color: #f63981 !important;
}

Маска для карты

Ну, и на закуску — очень простая вещь, но может для кого-нибудь окажется в новинку. По сути — просто блок на весь размер карты, либо являющийся картинкой, либо с фоновым изображением. Также есть свойство mask-image, но оно поддерживается не всеми браузерами.

Единственное, на что тут следует обратить внимание — css свойство pointer-events, которое на маске должно быть в значении none. Это позволит не учитывать этот блок в событиях мыши (проще говоря, кликать и скроллить сквозь этот блок).

image

На этом быстрый старт Google Maps окончен. Надеюсь, эта статья оказалась для вас полезной.

Исходники можно найти тут: GitHub