Этот пост будет небольшим, но надеюсь полезным. Сегодня я расскажу о том, как я реализовал поиск места на карте по его адресу, а также как я определяю текущее местоположение пользователя. Все это реализовано на основе 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/
Добавить комментарий