Як розмістити на сайті мапу від Google

Поширте інформацію:

В сьогоднішньому пості розглянемо роботу з Google Maps API v3 чере JavaScript.

  • Розмістимо на веб-сторінці карту частини Західної України
  • Встановимо позначки в потрібних місцях
  • Прив’яжемо до позначок віконця з інформацією, що будуть вигулькувати при клацанні мишею
  • Проведемо на карті автомобільний маршрут за допомогою служби Google Direction Service
  • Опрацюємо подію завершення завантаження мапи

Робота з Google Maps API v3 через JavaScript детально описана в навчальній інструкції. Тут буде дано робочий приклад коду та пояснено тонкощі його роботи.

Набільша проблема виникає з проведенням маршруту. Справа в тому, що служба Google Direction Service встановлює квоти та обмеження на її використання, і при частих запитах спрацьовує правильно “через раз”. Оновлюючи сторінку, бачиш, що іноді проводить маршрут нормально, а буває, що повертає неправильні результати із зайвими прямимим лініями:

Поганий результат

Щоб уникнути цієї проблеми, я раджу:

  1. Брати для позначення траси мінімально можливу кількість точок. В нашому прикладі цілком достатньо 3-х точок, хоча дорога не близька. Це не значить, що буде 2 відрізки між 3-ма точками. Direction Service сам передасть багато проміжних точок, потрібних для креслення правильної траси.
  2. Робити затримку між звертаннями до Google Direction Service

З мого досвіду, в результаті таких заходів “глюки” трапляються вкрай рідко, хоча іноді все-таки трапляються.

Тепер розміщую код з коментарями, а далі напишу пояснення.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <style type="text/css">
      html, body { height: 100%; margin: 0; padding: 0;}
      #splash {
        height: 20px;
        padding: 5px;
      }
      #map-canvas {height: 800px;}
    </style>
    <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js"></script>
    <script type="text/javascript">
function initialize() {
    var center = {lat: 50.00, lng: 25.50}; // Центр мапи: географічна широта і довгота
    var markers = [  // Точки, в яких будемо ставити позначки
        {
            "title": 'Львів', // Назва (підказка, що випливає при наведенні курсора миші)
            "lat": '49.840221', // Географічна широта
            "lng": '24.017666', // Географічна довгота
            "description": 'славне місто Львів', // Текст для інформаційного віконця
            "mark": true, // Ознака - встановлювати позначку в цій точці
            "forpath": true // Ознака - використовувати точку для прокладання маршруту
        },
        {
            "title": 'Золочів',
            "lat": '49.810612',
            "lng": '24.895924',
            "description": 'місто Золочів',
            "mark": true,
            "forpath": false
        },
        {
            "title": 'Тернопіль',
            "lat": '49.541226',
            "lng": '25.597669',
            "description": 'файне місто Тернопіль',
            "mark": true,
            "forpath": false
        },
        {
            "title": 'Волочиськ',
            "lat": '49.526194',
            "lng": '26.164845',
            "description": 'Волочиськ',
            "mark": true,
            "forpath": false
        },
        {
            "title": 'Хмельницький',
            "lat": '49.412735',
            "lng": '26.992933',
            "description": 'Проскурів-Хмельницький',
            "mark": true,
            "forpath": true
        },
        { 
            "title": 'Старокостянтинів',
            "lat": '49.760959',
            "lng": '27.214039',
            "description": 'місто Старокостянтинів',
            "mark": true,
            "forpath": false
        },
        {
            "title": 'Шепетівка',
            "lat": '50.181513',
            "lng": '27.049407',
            "description": 'місто Шепетівка',
            "mark": true,
            "forpath": true
        }

    ];

    // Параметри мапи
    var mapOptions = {
          center: center, // Центр
          zoom: 8         // Масштаб
    };

    // Завантаження мапи - змінна map зберігає посилання на нашу карту
    var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);

    var latlngbounds = new google.maps.LatLngBounds(); // Об’єкт для корекції прив’язки
    var infoWindow = new google.maps.InfoWindow(); // Об’єкт - інформаційне віконце
    var lat_lng = new Array(); // Масив, в який ми відберемо лише ті точки, що використовуються для прокладання маршруту

    // Перебір масиву точок
    for (var i = 0; i < markers.length; i++) {
        var data = markers[i];
        var myLatlng = new google.maps.LatLng(data.lat, data.lng); // Створюємо об’єкт - точка на мапі

        if (data.mark) { // Якщо потрібно - встановлюємо маркер (позначку)
            var marker = new google.maps.Marker({
                position: myLatlng,
                map: map,
                title: data.title
            });
            latlngbounds.extend(marker.position);

            // Встановлення обробника події 'click' для відображення інформаційного віконця
            // В кожній ітерації для створюваної функції-обробника треба зберігати копії об’єктів marker і data
            // Для цього застосовуємо "вираз з функцією негайного виконання" (IIFE or IEFE)
            (function (marker, data) {
                google.maps.event.addListener(marker, "click", function (e) {
                    infoWindow.setContent(data.description);
                    infoWindow.open(map, marker);
                });
            })(marker, data); // Передача актуальних параметрів в кожній ітерації
        }

        if (data.forpath) { // Якщо точка має брати участь в прокладені маршруту, зберігаємо її в масиві lat_lng
            lat_lng.push(new google.maps.LatLng(data.lat, data.lng));
        }
    }
    // Автокорекція центру і прив’язки відповідно до створених позначок
    map.setCenter(latlngbounds.getCenter());
    map.fitBounds(latlngbounds);

    // Прокладання маршруту
    var path = new google.maps.MVCArray(); // Об’єкт для зберігання даних маршруту
    var service = new google.maps.DirectionsService(); // Об’єкт для виклику служби Google Direction Service
    var poly = new google.maps.Polyline({ // Об’єкт, що креслить
        map: map,
        strokeColor: '#F3443C' // Колір "олівця"
    });

    // Перебір масиву точок, відібраних для креслення
    for (var i = 0; i < lat_lng.length; i++) {
        (function(i) { // для того, щоб функція setTimeout працювала в циклі,
                       // її також необхідно обгорнути у "вираз з функцією негайного виконання"
            if ((i+1) < lat_lng.length) { // опрацьовується пара точок в кожній ітерації, i-та та (i+1)-ша,
                                          // тому останню ітерацію пропускаємо
                var src = lat_lng[i]; // початок ділянки шляху
                var des = lat_lng[i+1]; // кінець ділянку шляху

                window.setTimeout(function() {
                    // Виклик Google Direction Service
                    service.route({
                        origin: src,
                        destination: des,
                        travelMode: google.maps.DirectionsTravelMode.DRIVING
                    }, function(result, status) { // Отримання результату
                        if (status == google.maps.DirectionsStatus.OK) {
                            // Якщо відповідь нормальна, опрацьовуємо її
                            for (var i = 0, len = result.routes[0].overview_path.length; i < len; i++) {
                                // Зберігаємо точки, по яких треба креслити
                                path.push(result.routes[0].overview_path[i]);
                            }
                            poly.setPath(path); // і креслимо
                        }
                    });
                }, i * 700); // викликаємо із затримкою 0.7 секунди на кожній ітерації
            }
        })(i); // передаємо актуальне значення лічильника циклу
    }

    // Коли настане подія 'idle' - сховати повідомлення про те, що мапа завантажується
    google.maps.event.addListenerOnce(map, 'idle', function(){
        document.getElementById("splash").style.visibility = 'hidden';
    });
}
google.maps.event.addDomListener(window, 'load', initialize);
    </script>
  </head>
  <body>
<div id="splash">Будь ласка, зачекайте хвилинку, завантажується мапа...</div>
<div id="map-canvas"></div>
  </body>
</html>

Отже, мінімальна розмітка HTML5, в тілі два елементи DIV. В першому напис “Зачекайте хвилинку…”, другий служить контейнером для карти. Карта має розмір, визначений контейнером, тому для контейнера необхідно задати розміри (чи, принаймні, висоту) в стилях.

#map-canvas {height: 800px;}

Підключення Google Maps API

<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js"></script>

Весь javascript-код містить функція initialize, рядок

google.maps.event.addDomListener(window, 'load', initialize);

встановлює обробник події “завантаження документу” для запуску цієї функції.

Точки на мапі задаються парами географічних координат: широтою(Latitude) і довготою (Longtitude) в градусах. На початку функції визначається точка центру мапи center і масив markers точок, які будуть використані для позначок і креслення маршруту. Зверніть увагу, що всього в масиві 7 точок, а для проведення маршруту будуть використані лише 3 з них (це задаємо ключем forpath).

Далі задаються параметри карти. Параметрів може бути багато, обов’язкових 2: center — центр карти і zoom масштаб (можна задавати від 0 до 20). Завантажується мапа, посилання на неї присвоюється змінній map.

Далі перебирається масив markers, встанолюються позначки за допомогою методів Google Maps API і відбираються в окремий масив lat_lng точки, необхідні для прокладання маршруту (див. коментарі).

Встановлення для позначки обробника події click обгорнуте у вираз з функцією негайного виконання. Це пов’язано з особливостями роботи циклів і замикань (функцій у функціях) у JavaScript. Якщо написати просто код

google.maps.event.addListener(marker, "click", function (e) {
    infoWindow.setContent(data.description);
    infoWindow.open(map, marker);
});

то для всіх створених позначок обробники події click будуть звертатися за посиланнями data і marker до однієї й тої самої області пам’яті, сформованої після закінчення циклу ітерацій (при i = 7, тобто до елемента масиву markers7, який не існує).

Щоб зрозуміти роботу функцій-замикань і виразів з функцією негайного виконання, раджу курити це і це, або це, або щось подібне. А може, я сам згодом напишу нашою мовою :)

Далі викликаються функції автокорекції центру і прив’язки карти відповідно до встановлених позначок і починається новий цикл перебору точок з масиву lat_lng, відібраних для креслення маршруту.

На кожному кроці визначається пара точок початок-кінець і передається в Google Direction Service. На основі відповідей цієї служби креслиться маршрут.

Як було сказано вище, між викликами служби організована затримка за допомогою функції setTimeout. Щоб функція setTimeout працювала в циклі правильно, її також треба обгорнути у вираз з функцією негайного виконання.

В кінці додається обробник для події ‘idle’, який ховає перший DIV з написом “Зачекайте хвилинку…”

Ось, що вийшло:

Карта

А ось наживо

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *

Цей сайт використовує Akismet для зменшення спаму. Дізнайтеся, як обробляються ваші дані коментарів.