Добро пожаловать во вторую и последнюю часть этой серии руководств по разработке приложения Exercise Tracker с PhoneGap. В этом уроке мы закончим страницу Track Workout и завершим приложение, создав страницы History и Track Info.
Сохранение данных GPS
Когда пользователь нажимает кнопку « Остановить отслеживание» , нам нужно прекратить отслеживать его местоположение GPS и сохранить все записанные точки GPS ( tracking_data
) в базу данных. Мы также сбросим поле ввода текста (если они захотят записать другую тренировку сразу) и отобразим сообщение о том, что мы прекратили отслеживание местоположения.
PhoneGap предоставляет как локальное хранилище на основе браузера, так и базу данных SQLite в качестве методов хранения данных на телефоне. База данных SQL намного мощнее (из-за того, что вы можете указывать схемы таблиц), но за счет сложности кода. Локальное хранилище — это простое хранилище ключей / значений, которое легко настроить и использовать. Данные хранятся с использованием setItem(key, value)
и извлекаются с использованием метода getItem(key)
.
В приложении ExerciseTracker нам нужно хранить tracking_data
(массив объектов Position). Мы установили для ключа значение track_id
(текст / идентификатор, введенный пользователем для своего упражнения), а значение — строковое представление объекта JSON tracking_data
. Мы вынуждены конвертировать этот массив в JSON, потому что Local Storage может хранить только строки.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
$(«#startTracking_stop»).live(‘click’, function(){
// Stop tracking the user
navigator.geolocation.clearWatch(watch_id);
// Save the tracking data
window.localStorage.setItem(track_id, JSON.stringify(tracking_data));
// Reset watch_id and tracking_data
var watch_id = null;
var tracking_data = null;
// Tidy up the UI
$(«#track_id»).val(«»).show();
$(«#startTracking_status»).html(«Stopped tracking workout: <strong>» + track_id + «</strong>»);
});
|
Ваше приложение теперь может отслеживать тренировки пользователя и хранить, где он пошел на телефоне!
Полезные ярлыки разработки
Теперь мы добавим в приложение пару функций, которые помогут сократить время разработки. На домашней странице ExerciseTracker вы запомните кнопки «Очистить локальное хранилище» и «Загрузить данные GPS для семян». В первом уроке мы только объявили разметку для них. Теперь мы будем кодировать функциональность.
Кнопки «Очистить локальное хранилище» и «Загрузить данные GPS о посеве» на главной странице.
Как и вся наша обработка событий в ExerciseTracker, мы используем функцию jQuery live()
для прослушивания события click. Если сработала кнопка «Очистить локальное хранилище», то мы вызываем метод window.localStorage.clear()
который удаляет все записи в локальном хранилище. Если кнопка «Load Seed GPS Data» сработала, мы вставляем некоторые фиктивные данные GPS в базу данных.
1
2
3
4
5
6
7
8
|
$(«#home_clearstorage_button»).live(‘click’, function(){
window.localStorage.clear();
});
$(«#home_seedgps_button»).live(‘click’, function(){
window.localStorage.setItem(‘Sample block’, ‘[{«timestamp»:1335700802000,»coords»:{«heading»:null,»altitude»:null,»longitude»:170.33488333333335,»accuracy»:0,»latitude»:-45.87475166666666,»speed»:null,»altitudeAccuracy»:null}},{«timestamp»:1335700803000,»coords»:{«heading»:null,»altitude»:null,»longitude»:170.33481666666665,»accuracy»:0,»latitude»:-45.87465,»speed»:null,»altitudeAccuracy»:null}},{«timestamp»:1335700804000,»coords»:{«heading»:null,»altitude»:null,»longitude»:170.33426999999998,»accuracy»:0,»latitude»:-45.873708333333326,»speed»:null,»altitudeAccuracy»:null}},{«timestamp»:1335700805000,»coords»:{«heading»:null,»altitude»:null,»longitude»:170.33318333333335,»accuracy»:0,»latitude»:-45.87178333333333,»speed»:null,»altitudeAccuracy»:null}},{«timestamp»:1335700806000,»coords»:{«heading»:null,»altitude»:null,»longitude»:170.33416166666666,»accuracy»:0,»latitude»:-45.871478333333336,»speed»:null,»altitudeAccuracy»:null}},{«timestamp»:1335700807000,»coords»:{«heading»:null,»alt
});
|
Страница истории
Завершенная страница истории
На странице истории перечислены все тренировки, записанные пользователем. Когда они нажимают на тренировку, мы открываем страницу «Информация о треке», которая содержит подробную информацию (например, пройденное расстояние, пройденное время и маршрут, нанесенный на карту Google). Ниже приведена разметка для страницы истории.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<div data-role=»page» id=»history»>
<div data-role=»header»>
<h1>History</h1>
<div data-role=»navbar»>
<ul>
<li><a href=»#home» data-transition=»none» data-icon=»home»>Home</a></li>
<li><a href=»#startTracking» data-transition=»none» data-icon=»plus»>Track Workout</a></li>
<li><a href=»#history» data-transition=»none» data-icon=»star»>History</a></li>
</ul>
</div>
</div>
<div data-role=»content»>
<p id=»tracks_recorded»></p>
<ul data-role=»listview» id=»history_tracklist»>
</ul>
</div>
</div>
|
Теперь нам нужно кодировать функциональность. Когда пользователь загружает страницу, нам нужно сгенерировать список HTML, содержащий все записанные тренировки. Поскольку window.localStorage
— это просто еще один объект Javascript, мы можем вызвать для него метод length()
чтобы узнать, сколько тренировок записал пользователь. Затем мы можем перебрать нашу базу данных, вызвав метод window.localStorage.key()
(который возвращает ключ для данного индекса), чтобы найти имена всех тренировок.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
// When the user views the history page
$(‘#history’).live(‘pageshow’, function () {
// Count the number of entries in localStorage and display this information to the user
tracks_recorded = window.localStorage.length;
$(«#tracks_recorded»).html(«<strong>» + tracks_recorded + «</strong> workout(s) recorded»);
// Empty the list of recorded tracks
$(«#history_tracklist»).empty();
// Iterate over all of the recorded tracks, populating the list
for(i=0; i<tracks_recorded; i++){
$(«#history_tracklist»).append(«<li><a href=’#track_info’ data-ajax=’false’>» + window.localStorage.key(i) + «</a></li>»);
}
// Tell jQueryMobile to refresh the list
$(«#history_tracklist»).listview(‘refresh’);
});
|
Страница просмотра истории теперь должна отображать все отслеживаемые тренировки.
Страница информации о треке
На странице «Информация о треке» отображается информация об отдельной тренировке, которую пользователь выполнил. Мы рассчитаем пройденное ими расстояние, время, которое им потребовалось для завершения тренировки, а также маршрут, пройденный на карте Google.
Страница с информацией о треке
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<div data-role=»page» id=»track_info»>
<div data-role=»header»>
<h1>Viewing Single Workout</h1>
<div data-role=»navbar»>
<ul>
<li><a href=»#home» data-transition=»none» data-icon=»home»>Home</a></li>
<li><a href=»#startTracking» data-transition=»none» data-icon=»plus»>Track Workout</a></li>
<li><a href=»#history» data-transition=»none» data-icon=»star»>History</a></li>
</ul>
</div>
</div>
<div data-role=»content»>
<p id=»track_info_info»></p>
<div id=»map_canvas» style=»position:absolute;bottom:0;left:0;width:100%;height:300px;»></div>
</div>
</div>
|
На странице «Информация о треке» отображается динамическая, а не статическая информация. Содержание страницы зависит от того, на какую тренировку щелкнул пользователь со страницы «История». Итак, нам нужен какой-то способ сообщить о том, какая тренировка была нажата, на странице «Информация о треке».
Когда пользователь щелкает ссылку тренировки, мы устанавливаем атрибут track_id
для track_id
<div id="track_info"></div>
. Затем, когда страница «Информация о треке» загружена, мы извлекаем этот track_id
и отображаем соответствующую информацию о тренировке.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
$(«#history_tracklist li a»).live(‘click’, function(){
$(«#track_info»).attr(«track_id», $(this).text());
});
// When the user views the Track Info page
$(‘#track_info’).live(‘pageshow’, function(){
// Find the track_id of the workout they are viewing
var key = $(this).attr(«track_id»);
// Update the Track Info page header to the track_id
$(«#track_info div[data-role=header] h1»).text(key);
// Get all the GPS data for the specific workout
var data = window.localStorage.getItem(key);
// Turn the stringified GPS data back into a JS object
data = JSON.parse(data);
|
Расчет дистанции тренировки
Крис Венесс написал отличное объяснение того, как рассчитать расстояние между двумя GPS-координатами. Я использовал его код в качестве основы для функции gps_distance
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
function gps_distance(lat1, lon1, lat2, lon2)
{
// http://www.movable-type.co.uk/scripts/latlong.html
var R = 6371;
var dLat = (lat2-lat1) * (Math.PI / 180);
var dLon = (lon2-lon1) * (Math.PI / 180);
var lat1 = lat1 * (Math.PI / 180);
var lat2 = lat2 * (Math.PI / 180);
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
return d;
}
|
Теперь, когда у нас есть функция для вычисления расстояния между двумя GPS-координатами и массивом, полным GPS-координат, записанных пользователем, мы можем суммировать все отдельные расстояния между соседними точками, чтобы вычислить общее расстояние, пройденное пользователем.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
// Calculate the total distance travelled
total_km = 0;
for(i = 0; i < data.length; i++){
if(i == (data.length — 1)){
break;
}
total_km += gps_distance(data[i].coords.latitude, data[i].coords.longitude, data[i+1].coords.latitude, data[i+1].coords.longitude);
}
total_km_rounded = total_km.toFixed(2);
|
Расчет продолжительности тренировки
Каждый из объектов GPS Position
имеет атрибут timestamp
. Мы просто вычитаем метку времени первой записанной позиции GPS из последней записанной позиции GPS, чтобы получить общее время, затраченное на тренировку в миллисекундах. Затем мы делаем некоторые преобразования, чтобы вычислить общее время в минутах и секундах.
01
02
03
04
05
06
07
08
09
10
11
12
|
// Calculate the total time taken for the track
start_time = new Date(data[0].timestamp).getTime();
end_time = new Date(data[data.length-1].timestamp).getTime();
total_time_ms = end_time — start_time;
total_time_s = total_time_ms / 1000;
final_time_m = Math.floor(total_time_s / 1000);
final_time_s = total_time_s — (final_time_m * 60);
// Display total distance and time
$(«#track_info_info»).html(‘Travelled <strong>’ + total_km_rounded + ‘</strong> km in <strong>’ + final_time_m + ‘m</strong> and <strong>’ + final_time_s + ‘s</strong>’);
|
Построение маршрута на карте Google
Наконец, нам нужно нанести маршрут тренировки на карту Google. Мы начнем с установки начальной широты и долготы, на которой будет центрирована Карта Google, в качестве координат первой точки GPS. Затем мы объявляем объект параметров, который содержит различные параметры для карты Google. Затем мы создаем карту, указывая, что мы хотим, чтобы элемент HTML с идентификатором map_canvas
карту.
01
02
03
04
05
06
07
08
09
10
11
12
|
// Set the initial Lat and Long of the Google Map
var myLatLng = new google.maps.LatLng(data[0].coords.latitude, data[0].coords.longitude);
// Google Map options
var myOptions = {
zoom: 15,
center: myLatLng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
// Create the Google Map, set options
var map = new google.maps.Map(document.getElementById(«map_canvas»), myOptions);
|
Если ваша карта не загружается, убедитесь, что вы указали правильный ключ API в <script src="">
API Карт Google в index.html. После создания нашей карты мы можем построить маршрут пользователя. Мы создаем массив и заполняем его экземплярами google.maps.LatLng
заменяющими значения каждой из точек GPS. Затем мы создаем google.maps.PolyLine
основе этих координат и применяем линию к карте.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
var trackCoords = [];
// Add each GPS entry to an array
for(i=0; i<data.length; i++){
trackCoords.push(new google.maps.LatLng(data[i].coords.latitude, data[i].coords.longitude));
}
// Plot the GPS entries as a line on the Google Map
var trackPath = new google.maps.Polyline({
path: trackCoords,
strokeColor: «#FF0000»,
strokeOpacity: 1.0,
strokeWeight: 2
});
// Apply the line to the map
trackPath.setMap(map);
|
Вывод
На этом мы завершаем учебник по созданию приложения PhoneGap ExerciseTracker. Я надеюсь, что вы многое узнали о различных технологиях, которые мы использовали. Если у вас есть какие-либо вопросы, пожалуйста, оставьте их в комментариях ниже!