Google Maps: выделение областей на карте

Владимир | | HTML, JavaScript, Web разработка.

google maps circle logo

О сервисах Google Maps и Яндекс.Карты слышали, наверное, практически все пользователи интернета. Но если для рядового пользователя их возможности ограничиваются стандартным интерфейсом, то для разработчиков всё гораздо интереснее.

Оба сервиса предоставляют API, который позволяет получить дополнительную информацию, изменить внешний вид и работу карт.

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

Прежде всего, сформулируем задачу.

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

Т.к. для обоих случаев API практически одинаков, рассмотрим вариант с окружностью.

Итак, принцип работы будет следующий.

1) Посетитель кликает по произвольной точке на карте, мы ставим на неё маркер (чтобы удобнее было ориентироваться) и считаем её центром области.

2) Посетитель кликает по любой точке на границе области. Мы рассчитываем расстояние от неё до центра (радиус) и строим окружность.

Если посетитель захочет изменить область, то ему будет достаточно снова сделать два клика. Мы убираем старую окружность и строим новую.

Поэкспериментировать с этим примером можно на демонстрационной страничке или, если хотите, качайте архив с исходными файлами.

Source

Переходим к реализации.

Прежде всего, создадим страницу с картой.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>Окружности на Google Maps</title>
</head>
<body>
    <div id="my_map" style="width:600px;height:400px"></div>
    <script src="main.js"></script>
</body>
</html>

Здесь всё предельно просто. Создаём блок для карты (my_map), указываем его размеры (600х400 px) и подключаем файл со скриптами (main.js), которые будут выполнять всю работу.

Рассмотрим подробнее main.js.

В первую очередь нам нужно подключить карту.

var map, circle, circleOptions, setCenter, marker;

function initialize() {
    var myLatlng = new google.maps.LatLng(50.45127, 30.523368); //Kiev
    var myOptions = {
        zoom: 9,
        center: myLatlng,
        mapTypeId: google.maps.MapTypeId.HYBRID
    }
    map = new google.maps.Map(document.getElementById("my_map"), myOptions);
}
  
function loadScript() {
    var script = document.createElement("script");
    script.src = "http://maps.google.com/maps/api/js?sensor=false&callback=initialize";
    document.body.appendChild(script);
}

window.onload = loadScript;

Работает этот код следующим образом. При возникновении события window.onload (завершена загрузка страницы) будет вызвана функция loadScript, которая добавит в конец страницы тег script, подключающий Google Maps.

Обратите внимание на GET параметр callback. В нём передаётся название функции (initialize), которая будет вызвана сразу после загрузки скрипта.

В этой функции (initialize) мы указываем настройки (координаты центра, приближение, тип карты) и создаём карту (строка 10).

В результате внутри блока my_map появится обычная карта Google.

Переходим к созданию окружности.

Прежде всего, немного теории.

С точки зрения API Google Maps, окружность (также как и многоугольник) является оверлеем (overlay). Для её создания используется класс google.maps.Circle, а однозначно задать её размещение можно с помощью центральной точки — center (объект типа LatLng в котором хранится широта и долгота) и радиуса — radius (в метрах).

Кроме того, в большинстве случаев желательно указать цвет окружности, её заливку и прозрачность. Параметры – fillColor, fillOpacity, strokeColor и strokeOpacity.

В нашем случае посетитель строит окружность с помощью кликов по карте, значит, нужно установить обработчик события click и в нём выполнять настройку и создание окружности.

Обработчик события click получит параметр event, который содержит координаты точки, по которой кликнул посетитель.

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

Теперь взгляните на код.

function initialize() {
    ......
    setCenter = true;
    
    circleOptions = {
        fillColor:"#00AAFF",
        fillOpacity:0.5,
        strokeColor:"#FFAA00",
        strokeOpacity:0.8,
        strokeWeight:2,
        clickable:false
    }

    google.maps.event.addListener(map, 'click', function(event) {
        if (setCenter) {
            if (marker != undefined) {
                marker.setMap(null);
            }
			marker = new google.maps.Marker({
				position:event.latLng,
				clickable:false
			});
			marker.setMap(map);
            circleOptions.center = event.latLng;
            setCenter = false;
        }
        else {
            //рассчитываем расстояние между точками
            var radius = distHaversine(circleOptions.center, event.latLng)
            circleOptions.radius = radius*1000;
            if (circle != undefined) {
                circle.setMap(null);
            }
            circle = new google.maps.Circle(circleOptions);
            circle.setMap(map);
            setCenter = true;
        }
    });
}

Нам нужно отличить первый клик от второго. Для этого используем переменную setCenter. Если она равна true, то в данный момент выполняется установка центра окружности.

В переменной circleOptions сохраняем хеш с начальными настройками окружности (цвет, прозрачность и т.п.).

После этого устанавливаем обработчик события click (строка 14).

Логика работы здесь следующая. Если setCenter == true (установка центра окружности), то мы убираем старый маркер (строки 16-18) и создаём новый в указанной точке (строки 19-23).

Затем, сохраняем центр окружности (параметр circleOptions.center) и присваиваем setCenter значение false (т.е. запоминаем, что следующий клик по карте укажет радиус окружности).

После второго клика мы рассчитываем расстояние (функция distHaversine, о ней чуть ниже) и устанавливаем параметр circleOptions.radius.

Затем убираем старую окружность (если она есть) и создаём новую (строки 31-35).

В результате на карте появится новая окружность.

Обратите внимание, что переменные map, circle, circleOptions, setCenter и marker объявлены в глобальной области видимости. Это необходимо, чтобы их значения сохранялись между вызовами обработчиков событий.

Теперь разберём функцию расчета расстояний между точками.

rad = function(x) {return x*Math.PI/180;}

distHaversine = function(p1, p2) {
    var R = 6371; // earth's mean radius in km
    var dLat  = rad(p2.lat() - p1.lat());
    var dLong = rad(p2.lng() - p1.lng());
    
    var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
            Math.cos(rad(p1.lat())) * Math.cos(rad(p2.lat())) * Math.sin(dLong/2) * Math.sin(dLong/2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    var d = R * c;
    
    return d.toFixed(3);
}

Это реализация формулы гавернсинусов на JavaScript. Взял я её здесь. Формула позволяет определить расстояние между двумя точками на поверхности сферы (длину дуги).

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

В нашем случае удобно, что приведённая функция правильно работает с объектом LatLng.

И в заключение, пару замечаний о хранении данных.

После кликов посетителя координаты области будут находиться в объекте circleOptions. Их можно передать на сервер, например, с помощью AJAX запроса. Таким образом, при повторном входе посетителя на сайт, можно будет восстановить область.

Вообще, применений этих возможностей масса, главное творчески подойти к их использованию 😉

Успехов!

Интересно почитать

Муляжи блюд — реклама кафе, которая убивает наповал.