Геокодирование адреса в координаты и геолокация текущего местоположения в OpenLayers

от автора

Привет, Хабр.

Этот пост будет небольшим, но надеюсь полезным. Сегодня я расскажу о том, как я реализовал поиск места на карте по его адресу, а также как я определяю текущее местоположение пользователя. Все это реализовано на основе OpenLayers 2.

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

На первом месте стоит геолокация. IMHO, благодаря OL этот вопрос не является трудоемким.

Сначала создадим нужный объект:

var control = new OpenLayers.Control.Geolocate(            bind: false,            watch: true,            geolocationOptions: {                     enableHighAccuracy: true,                     maximumAge: 0,                     timeout: 15000                 }); 

и добавим его на карту (OpenLayersMap — это собственно созданный объект карты после конструктора OpenLayers.Map(options)):

OpenLayersMap.addControl(control); 

С этим разобрались, но что же дальше. Дальше нужно его активировать. Опять-таки, все просто:

control.activate(); 

И последнее что я добавил — это обработчик события, когда местоположение найдено. Для этого регистрируем событие и указываем функцию для обработки этого события:

control.events.on({ "locationupdated": function(e) {                 OpenLayersFunc.Events.GeolocateOnLocationUpdated(e);                 } }) 

Теперь подготовим слой для отображения наших элементов:

var layer = new OpenLayers.Layer.Vector('Geolocate', {            styleMap: new OpenLayers.StyleMap(                     new OpenLayers.Style({                                   fillColor: '#000',                                   fillOpacity: 0.1,                                   strokeWidth: 0})                     ) }); OpenLayersMap.addLayer(layer); 

Осталось написать функцию OpenLayersFunc.Events.GeolocateOnLocationUpdated. Сам принцип действия таков. Когда срабатывает событие «locationupdated», вызывается наша функция, в которую передается event этого события. А уже в этой функции мы изгаляемся над ним, как хотим. Код я постарался прокомментировать, так что просто смотрим:

var vector = OpenLayersMap.getLayersByName('Geolocate')[0]; vector.removeAllFeatures(); //очистили слой геолокации (чтобы не было дубляжей) var polygon = OpenLayers.Geometry.Polygon.createRegularPolygon(new OpenLayers.Geometry.Point(e.point.x, e.point.y), e.position.coords.accuracy / 2, 40, 0); var circle = new OpenLayers.Feature.Vector(polygon); //создали геометрию круга вокруг точки нашего местоположения и создали объект слоя var point = new OpenLayers.Feature.Vector(e.point, {}, {             graphicName: 'cross',             strokeColor: '#f00',             strokeWidth: 1,             fillOpacity: 0,             pointRadius: 8         }); //также создаем саму точку vector.addFeatures([point, circle]); //и добавляем круг с точкой на слой if (OpenLayersFunc.Events.GeolocateFirstRun) { //это просто глобальная переменная, чтобы определить запускаем ли мы в первый раз             pulsate(circle); //а это уже красота, смотрим дальше             OpenLayersFunc.Events.GeolocateFirstRun = false;         } 

Функция pulsate добавляет анимацию пульсирования на круг. В параметре мы передаем объект нашего круга — circle. Смотрится довольно эффектно:

var pulsate = function(feature) {             var point = feature.geometry.getCentroid();             var bounds = feature.geometry.getBounds();             var radius = Math.abs((bounds.right - bounds.left) / 2);             var count = 0;             var grow = 'up';             var resize = function() {                 if (count > 16) {                     clearInterval(window.resizeInterval);                 }                 var interval = radius * 0.03;                 var ratio = interval / radius;                 switch (count) {                     case 4:                     case 12:                         grow = 'down';                         break;                     case 8:                         grow = 'up';                         break;                 }                 if (grow !== 'up') {                     ratio = -Math.abs(ratio);                 }                 feature.geometry.resize(1 + ratio, point);                 vector.drawFeature(feature);                 count++;             };             window.resizeInterval = window.setInterval(resize, 50, point, radius);         }; 

Весь код данной реализации под спойлером:

Геолокация

var layer = new OpenLayers.Layer.Vector('Geolocate', {            styleMap: new OpenLayers.StyleMap(                     new OpenLayers.Style({                                   fillColor: '#000',                                   fillOpacity: 0.1,                                   strokeWidth: 0})                     ) }); OpenLayersMap.addLayer(layer); var control = new OpenLayers.Control.Geolocate(            bind: false,            watch: true,            geolocationOptions: {                     enableHighAccuracy: true,                     maximumAge: 0,                     timeout: 15000                 }); OpenLayersMap.addControl(control); control.activate(); OpenLayersFunc.Events.GeolocateFirstRun = true; OpenLayersFunc.Events.GeolocateOnLocationUpdated = function(e) {         var vector = OpenLayersTools.Layers.GetLayerByName('Geolocate');         var pulsate = function(feature) {             var point = feature.geometry.getCentroid();             var bounds = feature.geometry.getBounds();             var radius = Math.abs((bounds.right - bounds.left) / 2);             var count = 0;             var grow = 'up';             var resize = function() {                 if (count > 16) {                     clearInterval(window.resizeInterval);                 }                 var interval = radius * 0.03;                 var ratio = interval / radius;                 switch (count) {                     case 4:                     case 12:                         grow = 'down';                         break;                     case 8:                         grow = 'up';                         break;                 }                 if (grow !== 'up') {                     ratio = -Math.abs(ratio);                 }                 feature.geometry.resize(1 + ratio, point);                 vector.drawFeature(feature);                 count++;             };             window.resizeInterval = window.setInterval(resize, 50, point, radius);         };         OpenLayersTools.Layers.ClearLayers(['Geolocate']);         var polygon = OpenLayers.Geometry.Polygon.createRegularPolygon(new OpenLayers.Geometry.Point(e.point.x, e.point.y), e.position.coords.accuracy / 2, 40, 0);         var circle = new OpenLayers.Feature.Vector(polygon);         var point = new OpenLayers.Feature.Vector(e.point, {}, {             graphicName: 'cross',             strokeColor: '#f00',             strokeWidth: 1,             fillOpacity: 0,             pointRadius: 8         });         vector.addFeatures([point, circle]);         if (OpenLayersFunc.Events.GeolocateFirstRun) {             pulsate(circle);             OpenLayersFunc.Events.GeolocateFirstRun = false;         }     }; control.events.on({ "locationupdated": function(e) {                 OpenLayersFunc.Events.GeolocateOnLocationUpdated(e);                 } }) 

Перейдем теперь к очень похожей вещи — геокодирование. Я использовал апи от гуглов и не жалею. Начнем:

Сначала создали еще один слой для отображения маркера с попапом:

var layer = new OpenLayers.Layer.Vector('Geocoder', {            styleMap: new OpenLayers.StyleMap(                     new OpenLayers.Style({                                  externalGraphic: '../images/geocoder_marker.png',                                  graphicWidth: 32,                                  graphicHeight: 32,                                  graphicYOffset: -32                     ) }); 

Здесь все намного проще. Одна функция и та, от jQuery, чтобы сделать все красиво. Создаем объект геокодирования, делаем запрос гуглам, получаем результат и парсим для jquery-ui.autocomplete на source. А на select вешаем центрирование карты на этот адрес и добавляем маркер с окошком адреса:

var geocoder = new google.maps.Geocoder(); //создаем объект геокодирования     $('#top-search-field').autocomplete({ //подключаем плагин к нашему полю ввода         source: function(request, response) { //заполняем автодополнение результатами возможных адресов             geocoder.geocode({'address': request.term}, function(results, status) { //отправляем введенный текст                 response($.map(results, function(item) { //и получаем список возможных вариантов адресов                     return { //какую мы и генерируем в объект для autocomplete                         label: item.formatted_address,                         value: item.formatted_address,                         latitude: item.geometry.location.lat(),                         longitude: item.geometry.location.lng()                     };                 }));             });         },         select: function(event, ui) { //в случае выбора некого пункта             var layer = OpenLayersMap.getLayersByName('Geocoder')[0];             layer.removeAllFeatures(); //очищаем слой от предыдущих объектов             var point_popup = new OpenLayers.LonLat(ui.item.longitude, ui.item.latitude); //создаем координаты для попапа             point_popup.transform(new OpenLayers.Projection("EPSG:4326"), OpenLayersMap.getProjectionObject()); //и переводим в другую проекцию             var point = new OpenLayers.Geometry.Point(ui.item.longitude, ui.item.latitude); //создаем точку             point.transform(new OpenLayers.Projection("EPSG:4326"), OpenLayersMap.getProjectionObject());             var feature = new OpenLayers.Feature.Vector(point); //создаем объект точки             var popup = new OpenLayers.Popup.FramedCloud('geocoder_marker', point_popup, new OpenLayers.Size(200, 50), ui.item.label, null, false, true); //создаем попап             OpenLayersTools.BaseFunc.CenterMap(ui.item.longitude, ui.item.latitude, 'EPSG:4326'); //центрируем на координатах адреса             popup.closeOnMove = true; //выставляем свойство, при движении карты закрыть попап             OpenLayersMap.addPopup(popup);             layer.addFeatures(feature); //и добавляем все это на карту и слой         }     }); 

Полный код даже незачем вешать, он и так весь сверху 🙂

P.S. Попробовал вот такое написать, не знаю, получилось или нет. Но все равно жду конструктивной критики, пожелания 🙂

ссылка на оригинал статьи http://habrahabr.ru/post/166215/


Комментарии

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

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