Карты Google в OpenLayers 3?

Когда я рассматривал подключение популярных слоев, я не упомянул о картах Google. Возможно, некоторым показалось странным, что в статье были затронуты карты Stamen, которые мало знакомы широкой аудитории, но не было и слова об одном из самых популярных картографических сервисов. Здесь мы рассмотрим, как подключить карты Google в OpenLayers 3, и почему эта тема заслуживает отдельной статьи.


Подключение карты Google я бы отнес к теме «если нельзя, но очень хочется». Дело в том, что OpenLayers 3 не поддерживает карты Google. Вообще. Прошло то замечательное время, когда достаточно было создать слой OpenLayers.Layer.Google и подключить его в карту OpenLayers 2. Тема по поддержке Google поднималась не один раз, разработчики всякий раз давали от ворот поворот, и пользователи вынуждены были оставаться на все более устаревающей версии OpenLayers 2 или переходили на Leaflet (в котором, кстати, поддержка карт Google и Яндекс реализована значительно лучше). Разработчики OL3 объяснили свой отказ тем, что использование карт Google возможно только через Google Maps API, а получать тайлы напрямую — это грубое нарушение политики Google. Поддержка слоев Google во второй версии давалась большим трудом и несколько раз ломалась при обновлении API. Переносить такой «костыль» никто не захотел и мы остались без Google. Ну или почти без него 🙂 .

Вся суть технологии по подключению слоев через API очень проста. Создается две карты — отдельно OpenLayers 3, отдельно Google — затем карты накладываются друг на друга, чтобы OL3 оказался выше. Далее добавляем обработчики на перемещение карты OL3 и сразу же передаем их в карту Google через вызовы API. Технически решение работает, но на практике есть куча проблем, о которых скажу позже.

Первым делом создаем контейнеры для Google и для OpenLayers:


    <div id="gmap" style="position: absolute; height: 400px;"></div>
    <div id="olmap" style="height: 400px;"></div>


Далее создадим карту Google. Опции конструктора вроде disableDefaultUI и disableDoubleClickZoom делают карту Google «немой» — она ни на что не реагирует и не имеет своих контролов. Это нам и нужно, ведь дирижером будет выступать OL3:


    var gmap = new google.maps.Map(document.getElementById('gmap'), {
        disableDefaultUI: true,
        keyboardShortcuts: false,
        draggable: false,
        disableDoubleClickZoom: true,
        scrollwheel: false,
        streetViewControl: false
    });


Теперь, когда у нас есть объекта карты Google, инициализируем карту OL3:


    var map = new ol.Map({
        interactions: ol.interaction.defaults({
            altShiftDragRotate: false,
            dragPan: false,
            rotate: false
        }).extend([new ol.interaction.DragPan({kinetic: null})]),
        target: 'olmap'
    });


Метод ol.interaction.defaults возвращает набор объектов взаимодействия с картой по умолчанию. Мы отключаем вращение карты и переопределяем DragPan таким образом, чтобы не было поведения kinetic (кинетическое движение карты, когда она продолжает перемещаться некоторое время после отпускания мыши), так как с Google эта штука работает не плавно, а рывками. Теперь создадим объект ol.View, который будет отвечать за синхронизацию между картами:


    var view = new ol.View({
        // за 21 зумом теряется синхронизация OL3 и Google,
        // поэтому устанавливаем ограничение на максимальный зум
        maxZoom: 21
    });
    
    // при изменении центра переводим координаты в EPSG:4326 и устанавливаем карте Google
    view.on('change:center', function() {
        var center = ol.proj.transform(view.getCenter(), 'EPSG:3857', 'EPSG:4326');
        gmap.setCenter(new google.maps.LatLng(center[1], center[0]));
    });
    
    // аналогично при изменении зума OL3 меняем зум Google
    view.on('change:resolution', function() {
        gmap.setZoom(view.getZoom());
    });
    map.setView(view);
    
    // устанавливаем центр и зум, чтобы сработали события синхронизации карты
    view.setCenter([ 1927436.1052390044, 6437832.270290685 ]);
    view.setZoom(4);


После этого карта уже будет работать, но добавим еще точки городов из предыдущего поста (но не в виде тепловой карты, а обычными точками), чтобы было видно, что данные OL3 расположены правильно на карте Google — и цель можно считать достигнутой:


    var vector = new ol.layer.Vector({
        source: new ol.source.Vector({
            url: 'cities.json',
            format: new ol.format.GeoJSON()
        })
    });


Несмотря на то, что вариант вполне рабочий, я бы не советовал использовать его в реальных проектах. Google остается инородным телом, это не часть карты OpenLayers, следовательно, мы не можем задать ему прозрачность через setOpacity, не можем управлять видимостью через setVisible, а все сложности по управлению берем на себя. Кроме того, он ограничивает нас в функционале (тот же поворот карты или kinetic не работают в этой связке). Но иногда приходится скрипеть зубами и подстраиваться под требования. И если вдруг вам придется есть этот кактус, то я надеюсь, что немного смягчил его иголки 😉 .




Ссылки:

Карты Google в OpenLayers 3?
Метки:    

2 thoughts on “Карты Google в OpenLayers 3?

  • 15.06.2016 at 23:59
    Permalink

    Продолжай пожалуйста. Интересно, как делать маркеры, полигоны, считать километры и метры между точками.

    Ответить
    • 16.06.2016 at 22:47
      Permalink

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

      Ответить

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *