Добро пожаловать в четвертую часть моей серии блогов по созданию приложения PhoneGap с поддержкой Parse.com . Если вы еще не читали более ранние записи в этой серии, пожалуйста, смотрите ссылки внизу для фона и истории до сих пор. В сегодняшней записи мы собираемся добавить геолокацию в приложение. Это будет поддерживаться как в механизме создания отчетов, так и на странице, которая получает советы.
К счастью, Parse.com делает создание приложений с учетом местоположения очень простым. На самом деле код этих функций настолько прост, что вы можете добавить их в течение пяти минут. К сожалению, не так просто решить, как использовать эти функции. Я нахожу, что все больше и больше это не столько проблема «Как я делаю Х», но и больше «Как сделать IX так, чтобы лучше всего работать для моих пользователей». Примите во внимание тот простой факт, что геолокация может — и не может — потерпеть неудачу. Что мне делать? Разрешить ли пользователям вводить адрес? Отображать ли маленькую карту, чтобы они могли коснуться, чтобы выбрать свое местоположение? Что если они лгут? Или что, если они просто неправы?
В конце концов — я не думаю, что я эксперт по пользовательскому интерфейсу. Как и большинство людей, я узнаю хороший UX по сравнению с плохим UX, но гораздо труднее решить, какой вариант лучше выбрать при создании собственных приложений. Надеюсь, через год или два я могу с уверенностью сказать, что я принимаю правильные решения. Пока что я собираюсь пройти через это (и, конечно, поделюсь этой борьбой с вами, ребята).
Сейчас я решил сделать геолокацию обязательной. Для добавления подсказки вам будет запрещено сохранять данные, если проверка геолокации не удалась. Для отображения подсказок, если мы не можем получить ваше местоположение, мы не беспокоимся о получении каких-либо сохраненных данных.
Давайте начнем с рассмотрения изменений на странице формы подсказки. Первым делом я добавил «отключено» как атрибут к кнопке отправки. Это означает, что страница загружается с немедленно отключенной формой. Затем я написал следующий фрагмент, который будет выполняться при загрузке страницы добавления.
if($("#addTipBtn").length === 1) { currentLocation=null; navigator.geolocation.getCurrentPosition(function(pos) { //store the long/lat currentLocation = {longitude:pos.coords.longitude, latitude:pos.coords.latitude}; $("#addTipBtn").removeAttr("disabled"); }, function(err) { //Since geolocation failed, we can't allow the user to submit doAlert("Sorry, but we couldn't find your location.\nYou may not post a cow tip."); }); }
currentLocation определен в корне моего файла JavaScript, поэтому он является глобальной переменной. Если все работает хорошо, тогда мы просто включаем кнопку формы. В противном случае пользователь получает ошибку.
Как только мы узнаем местоположение пользователя, как его сохранить? Parse.com поддерживает так называемые GeoPoints . Любой тип данных Parse.com может поддерживать геопункт, но только один. Геопункт — это просто пара данных долгота / широта. Используя это довольно просто, хотя. Рассмотрим этот код, взятый из обработчика отправки формы.
var tip = new TipObject(); var point = new Parse.GeoPoint({latitude: currentLocation.latitude, longitude: currentLocation.longitude}); tip.save( { numcows:numcows, howdangerous:howdangerous, comments:comments, location:point },{ success:function(object) { console.log("Saved object"); doAlert("Tip Saved!", function() { document.location.href='index.html'; }); }, error:function(model, error) { console.log("Error saving"); } });
По сравнению с нашим предыдущим примером, есть только два изменения. Во-первых, я делаю Geopoint с моими данными о местоположении. Затем я просто добавляю это значение к объекту tip. Помните, что я сказал, что мы можем — если мы хотим — изменить структуру наших данных в любое время. После выпуска приложения это, вероятно, плохая идея (и я расскажу о том, как этого можно избежать в следующей записи), но пока она довольно полезна.
Вот и все, что касается хранения. Любые записи, созданные с этим геопунктом, теперь можно искать новыми и интересными способами. Если вы помните, наш предыдущий код для страницы «get» забрал все из базы данных. Это было так просто, как создать запрос и просто запустить поиск по нему. Я хотел бы, чтобы это было более сложным.
Вот тут-то и начинает играть красота системы запросов Parse.com. Если мы хотим отфильтровать результаты, мы можем просто добавить дополнительные параметры для объекта. Например, при условии, что у меня есть ваше местоположение, требуется одна строка, чтобы найти данные рядом с вами:
query.near("location", myLocation);
Серьезно — вот и все. В моих тестах это было в пределах 50 миль или около того. Как ни странно, документы для «рядом» не указывают, что именно рядом. Рядом как Солнце? Рядом, как Starbucks? Я просто не уверен. Тем не менее, они предоставляют несколько альтернатив. Это гораздо сложнее, хотя. Вместо того, чтобы печатать рядом, я должен набрать «insideMiles»:
query.withinMiles("location", myLocation, 30);
Да, я немного осел, но не могу не подчеркнуть, насколько это круто. (Если вы не живете в надлежащей стране с имперскими подразделениями, они также поддерживают километры.) Я решил, что для моего приложения я хочу вернуть подсказки в пределах 30 миль и отчеты, которые были не старше 7 дней. Добавление фильтра даты было тремя строками кода, которые я мог бы написать как одну:
var lastWeek = new Date(); lastWeek.setDate(lastWeek.getDate()-7); query.greaterThan("createdAt", lastWeek);
Вот вся логика для получения данных на странице Get.
if($("#tipdisplay").length === 1) { //Update status to let the user know we are doing important things. Really important. $("#tipdisplay").html("Please stand by. Checking your location for nearby cow tips!"); navigator.geolocation.getCurrentPosition(function(pos) { var myLocation = new Parse.GeoPoint({latitude: pos.coords.latitude, longitude: pos.coords.longitude}); //Begin our query var query = new Parse.Query(TipObject); //Only within 30 miles query.withinMiles("location", myLocation, 30); //only within last week var lastWeek = new Date(); lastWeek.setDate(lastWeek.getDate()-7); query.greaterThan("createdAt", lastWeek); query.find({ success:function(results) { renderResults(results,myLocation); }, error: function(error) { alert("Error: " + error.code + " " + error.message); } }); }, function(err) { //Since geolocation failed, we can't allow the user to submit doAlert("Sorry, but we couldn't find your location."); },{timeout:20000,enableHighAccuracy:false}); }
Вы можете заметить, что я переместил часть рендера в его собственную функцию. Для картографической части этого приложения я решил попробовать бесплатный картографический сервис Leaflet . Листовка не только бесплатна, но и очень проста в использовании. Вот функция, которую я использую для рендеринга на карту:
function renderResults(results,myLoc) { console.log("renderResults: "+results.length); $("#tipdisplay").html("Displaying tips within 30 miles and from the last 7 days."); var map = L.map('map').setView([myLoc.latitude, myLoc.longitude], 8); var layerOpenStreet = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {maxZoom:18, minZoom:1, attribution:'Map data © 2012 OpenStreetMap'}).addTo(map); var dangerLevels = ["Totally Safe","Some Risk","Farmer with Shotgun!"]; for(var i=0, len=results.length; i<len; i++) { var result = results[i]; var marker = L.marker([result.attributes.location.latitude, result.attributes.location.longitude]).addTo(map); var markerLabel = "Cows: "+result.attributes.numcows+"<br/>Danger: "+dangerLevels[result.attributes.howdangerous-1]; if(result.attributes.comments && result.attributes.comments.length) markerLabel += "<br>"+result.attributes.comments; marker.bindPopup(markerLabel); } }
Даже если вы никогда не видели Leaflet раньше, вы, вероятно, можете прочитать это достаточно легко и посмотреть, что он делает. Для каждого результата я добавляю маркер вместе с небольшим информационным окном, которое вы можете нажать, чтобы получить подробную информацию. Вы можете увидеть пример этого ниже:
В общем, теперь у меня есть полное, хотя и базовое, приложение. Не забывайте, что вы можете увидеть полный исходный код приложения на GitHub Repo, и вы можете скачать сборки приложения на общедоступном сайте PhoneGap Build .
В следующей и последней части этой серии я собираюсь обсудить, что можно и нужно делать как на стороне PhoneGap, так и на стороне Parse.com.