Как показать на Google Maps объекты, находящиеся в заданной области

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

google maps

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

Начнём с постановки задачи

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

Будем считать, что заданная область представляет собой окружность, т.е. мы знаем координаты её центра и радиус. А координаты объектов находятся в KML файле (это XML формат, разработанный для описания объектов на Google maps).

Таким образом, алгоритм расстановки объектов получается довольно простым.

1) Читаем координаты объекта из KML файла.
2) Рассчитываем расстоянием между центром окружности и текущим объектом.
3) Если это расстояние меньше радиуса окружности, ставим маркер, если больше – пропускаем объект.

Переходим к решению.

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

Source

Серверная часть

Начнем с серверного скрипта, который формирует страницу с картой (index.php).

<?php
$organizations = simplexml_load_file('doc.kml');

$organizations_data = array();

foreach ($organizations->Folder->Placemark as $organisation) {
    $organizations_data[] = array(
        'name' => (string)$organisation->name,
        'coordinates' => (string)$organisation->Point->coordinates,
    );
}
?>

<!DOCTYPE html>

<html>
<head>
    <meta charset="UTF-8" />
    <title>Объекты на Google Maps</title>
    <script>
<?php
    echo 'var organizations = '.json_encode($organizations_data).';';
?>
    </script>
</head>

<body>

<h1>Google Maps: отображение объектов, которые находятся в заданной области</h1>

<div id="my_map" style="width:600px;height:400px"></div>

<script src="main.js"></script>
</body>
</html>

Прежде всего, загружаем данные из KML файла (строка 2). Т.к. это обычный XML файл, то мы можем использовать любую библиотеку для работы с этим форматом. В данном случае – SimpleXML.

Затем, необходимо обеспечить доступ к этим данным на клиентской стороне, т.к. настройка Google Maps выполняется с помощью JavaScript.

Для этого мы формируем массив с необходимыми данными (строки 6-11), преобразовываем его в JSON формат (строка 22) и присваиваем переменной organizations (строка 22) в теге script. Таким образом, мы получаем JavaScript массив с координатами всех объектов из KML файла.

Тут я хочу сделать небольшое отступление. В принципе, работать с KML файлом можно и на стороне браузера, это несложно. Но в общем случае, этот файл не обязательно будет находиться на вашем сервере, а кросс-доменные (XSS) запросы запрещены политикой безопасности браузеров. Т.е. придётся искать какой-нибудь обходной путь. Подробнее на эту тему можно почитать здесь, здесь, здесь и здесь.

Подробно разбирать работу с SimpleXML, думаю, смысла не имеет. Для данного примера достаточно понимать, что после загрузки файла вы получите объект, имеющий такую же структуру как и xml-документ.

Т.е. вызов $organizations->Folder->Placemark вернет вам содержимое тега <Placemark> в документе с такой структурой

<kml xmlns="…" xmlns:kml="…" xmlns:atom="…">
<Folder>
	<Placemark>
	…
	</Placemark>
</Folder>
</kml>

Обратите внимание! Библиотека чувствительна к регистру тегов в xml-файле.

На самой странице мы создаём блок для карты (my_map).

И подключаем файл main.js, который и будет выполнять настройку карты.

Клиентская часть

Сразу посмотрим на весь скрипт целиком.

var map, circle, circleOptions, setCenter, marker, organizations_markers;

function initialize() {
    var centerPoint = new google.maps.LatLng(48.67, 44.47); //Волгоград
    var myOptions = {
        zoom: 12,
        center: centerPoint,
        mapTypeId: google.maps.MapTypeId.HYBRID
    }
    map = new google.maps.Map(document.getElementById("my_map"), myOptions);
    
    //радиус окружности - 5 км
    var radius = 5;
    
    circleOptions = {
        center: centerPoint,
        fillColor: "#00AAFF",
        fillOpacity: 0.5,
        strokeColor: "#FFAA00",
        strokeOpacity: 0.8,
        strokeWeight: 2,
        clickable: false,
        radius: radius*1000
    }

    //рисуем окружность
    circle = new google.maps.Circle(circleOptions);
    circle.setMap(map);

    //устанавливаем маркеры организаций
    organizations_markers = [];
    for (var i = 0; i &lt; organizations.length; i++) {
        var ll = organizations[i].coordinates.split(',');
        var latlng = new google.maps.LatLng(ll[1], ll[0]);
        if (distHaversine(latlng, centerPoint) &lt; radius) {
            organizations_markers[i] = new google.maps.Marker({
                    position:latlng,
                    clickable:true
                });
            organizations_markers[i].setMap(map);
        }
    }
}
  
function loadScript() {
    var script = document.createElement("script");
    script.src = "http://maps.google.com/maps/api/js?sensor=false&callback=initialize";
    document.body.appendChild(script);
}

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);
}

window.onload = loadScript;

В первую очередь мы создаём карту и устанавливаем её основные параметры (координаты центра, приближение). Для этого, назначаем обработчик событию window.onload (строка 69). Этот обработчик добавляет на страницу тег script в параметре src которого передается адрес имя метода, который будет вызван после загрузки Google Maps (в данном случае — initialize). Таким образом, все наши настройки выполняются в этом методе.

Выполняем установку параметров карты (строки 4-10). Мы указали: центральную точку (centerPoint), приближение (zoom) и тип карты (mapTypeId).

Теперь рисуем окружность (строки 13-28). Её центр совпадает с центром карты, а радиус равен 5 км. В настройках окружности указываем толщину и цвет линии, цвет и прозрачность фона и другие параметры.

После этого расставляем маркеры объектов.

Напомню, что координаты этих объектов находятся в массиве organizations, который был сформирован серверным скриптом.

Т.е. нам нужно пройтись по всем элементам этого массива и рассчитать расстояние от центра окружности до текущего объекта (строки 31-42).

Расчет расстояний для точек на поверхности Земли выполняется с помощью функции гаверсинусов (distHaversine). Её реализацию на JavaScript я взял здесь.

Если это расстояние меньше заданного, создаём маркер и показываем его на карте (строки 36-40). В противном случае – переходим к следующему объекту.

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

Если есть вопросы или замечания, пишите, постараюсь ответить в комментариях 😉

Успехов!

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

Хотите создать свой сайт? Template CMS — быстрая и маленькая CMS! Поможет решить эту задачу с минимальными затратами времени и ресурсов.

В раздумьях, что подарить на свадьбу друзьям? Попробуйте свадебную фотокнигу.

Заполним 3-ндфл за 2011 год за 1 день, от 500 рублей!