Статьи

Создание приложения для отслеживания упражнений: постоянство и отображение

Добро пожаловать во вторую и последнюю часть этой серии руководств по разработке приложения Exercise Tracker с PhoneGap. В этом уроке мы закончим страницу Track Workout и завершим приложение, создав страницы History и Track Info.


Когда пользователь нажимает кнопку « Остановить отслеживание» , нам нужно прекратить отслеживать его местоположение 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 для семян». В первом уроке мы только объявили разметку для них. Теперь мы будем кодировать функциональность.

Home page

Кнопки «Очистить локальное хранилище» и «Загрузить данные 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
 
});

history

Завершенная страница истории

На странице истории перечислены все тренировки, записанные пользователем. Когда они нажимают на тренировку, мы открываем страницу «Информация о треке», которая содержит подробную информацию (например, пройденное расстояние, пройденное время и маршрут, нанесенный на карту 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.

track info page

Страница с информацией о треке

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, в качестве координат первой точки 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. Я надеюсь, что вы многое узнали о различных технологиях, которые мы использовали. Если у вас есть какие-либо вопросы, пожалуйста, оставьте их в комментариях ниже!