413 lines
12 KiB
JavaScript
Executable File
413 lines
12 KiB
JavaScript
Executable File
/* phpTrackme
|
|
*
|
|
* Copyright(C) 2013 Bartek Fabiszewski (www.fabiszewski.net)
|
|
*
|
|
* This is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU Library General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
// google maps
|
|
function displayTrack(xml,update) {
|
|
altitudes.length = 0;
|
|
var totalMeters = 0;
|
|
var totalSeconds = 0;
|
|
// init polyline
|
|
var poly = new google.maps.Polyline(polyOptions);
|
|
poly.setMap(map);
|
|
var path = poly.getPath();
|
|
var latlngbounds = new google.maps.LatLngBounds( );
|
|
var positions = xml.getElementsByTagName('position');
|
|
var posLen = positions.length;
|
|
for (var i=0; i<posLen; i++) {
|
|
var p = parsePosition(positions[i]);
|
|
totalMeters += p.distance;
|
|
totalSeconds += p.seconds;
|
|
p['totalMeters'] = totalMeters;
|
|
p['totalSeconds'] = totalSeconds;
|
|
p['coordinates'] = new google.maps.LatLng(p.latitude,p.longitude);
|
|
// set marker
|
|
setMarker(p,i,posLen);
|
|
// update polyline
|
|
path.push(p.coordinates);
|
|
latlngbounds.extend(p.coordinates);
|
|
// save altitudes for chart
|
|
altitudes[i] = p.altitude;
|
|
}
|
|
if (update) {
|
|
map.fitBounds(latlngbounds);
|
|
if (i==1) {
|
|
// only one point, zoom out
|
|
zListener =
|
|
google.maps.event.addListenerOnce(map, 'bounds_changed', function(event) {
|
|
if (this.getZoom()){
|
|
this.setZoom(15);
|
|
}
|
|
});
|
|
setTimeout(function(){google.maps.event.removeListener(zListener)}, 2000);
|
|
}
|
|
}
|
|
latestTime = p.dateoccured;
|
|
polies.push(poly);
|
|
|
|
updateSummary(p.dateoccured,totalMeters,totalSeconds);
|
|
if (p.tid!=trackid) {
|
|
trackid=p.tid;
|
|
setTrack(trackid);
|
|
}
|
|
if (document.getElementById('bottom').style.display=='block') {
|
|
// update altitudes chart
|
|
chart.clearChart();
|
|
displayChart();
|
|
}
|
|
}
|
|
|
|
function clearMap(){
|
|
if (polies){
|
|
for (var i=0; i<polies.length; i++){
|
|
polies[i].setMap(null);
|
|
}
|
|
}
|
|
if (markers){
|
|
for (var i=0; i<markers.length; i++){
|
|
google.maps.event.removeListener(popups[i].listener);
|
|
popups[i].setMap(null);
|
|
markers[i].setMap(null);
|
|
}
|
|
}
|
|
markers.length = 0;
|
|
polies.length = 0;
|
|
popups.lentgth = 0;
|
|
}
|
|
|
|
var popup;
|
|
function setMarker(p,i,posLen) {
|
|
// marker
|
|
var marker = new google.maps.Marker( {
|
|
map: map,
|
|
position: p.coordinates,
|
|
title: p.dateoccured
|
|
});
|
|
if (latest==1) { marker.setIcon('http://maps.google.com/mapfiles/dd-end.png') }
|
|
else if (i==0) { marker.setIcon('http://maps.google.com/mapfiles/marker_greenA.png') }
|
|
else if (i==posLen-1) { marker.setIcon('http://maps.google.com/mapfiles/markerB.png') }
|
|
else { marker.setIcon('http://labs.google.com/ridefinder/images/mm_20_gray.png') }
|
|
// popup
|
|
var content = '<div id="popup">'+
|
|
'<div id="pheader">'+lang_user+': '+p.username.toUpperCase()+'<br />'+lang_track+': '+p.trackname.toUpperCase()+
|
|
'</div>'+
|
|
'<div id="pbody">'+
|
|
'<div id="pleft"><b>'+lang_time+':</b> '+p.dateoccured+'<br />'+
|
|
((p.speed != null)?'<b>'+lang_speed+':</b> '+(p.speed.toKmH()*factor_kmh)+' '+unit_kmh+'<br />':'')+
|
|
((p.altitude != null)?'<b>'+lang_altitude+':</b> '+(p.altitude*factor_m).toFixed()+' '+unit_m+'<br />':'')+'</div>'+
|
|
((latest==0)?
|
|
('<div id="pright"><b>'+lang_ttime+':</b> '+p.totalSeconds.toHMS()+'<br />'+
|
|
'<b>'+lang_aspeed+':</b> '+((p.totalSeconds>0)?((p.totalMeters/p.totalSeconds).toKmH()*factor_kmh).toFixed():0)+' '+unit_kmh+'<br />'+
|
|
'<b>'+lang_tdistance+':</b> '+(p.totalMeters.toKm()*factor_km).toFixed(2)+' '+unit_km+'<br />'+'</div>'):'')+
|
|
'<div id="pfooter">'+lang_point+' '+(i+1)+' '+lang_of+' '+(posLen)+'</div>'+
|
|
'</div></div>';
|
|
popup = new google.maps.InfoWindow();
|
|
popup.listener = google.maps.event.addListener(marker, 'click', (function(marker,content) {
|
|
return function() {
|
|
popup.setContent(content);
|
|
popup.open(map, marker);
|
|
if (document.getElementById('bottom').style.display=='block') {
|
|
chart.setSelection([{row:i,column:null}]);
|
|
}
|
|
}
|
|
})(marker,content));
|
|
markers.push(marker);
|
|
popups.push(popup);
|
|
}
|
|
|
|
|
|
|
|
// openstreetmaps
|
|
// TODO
|
|
|
|
|
|
// general stuff
|
|
if (units=='imperial') {
|
|
factor_kmh = 0.62; //to mph
|
|
unit_kmh = 'mph';
|
|
factor_m = 3.28; // to feet
|
|
unit_m = 'ft';
|
|
factor_km = 0.62; // to miles
|
|
unit_km = 'mi';
|
|
}
|
|
else {
|
|
factor_kmh = 1;
|
|
unit_kmh = 'km/h';
|
|
factor_m = 1;
|
|
unit_m = 'm';
|
|
factor_km = 1;
|
|
unit_km = 'km';
|
|
}
|
|
var latest = 0;
|
|
var latestTime = 0;
|
|
var live = 0;
|
|
var chart;
|
|
var altitudes = new Array();
|
|
var altTimeout;
|
|
function displayChart() {
|
|
if (chart) { google.visualization.events.removeAllListeners(chart); }
|
|
var data = new google.visualization.DataTable();
|
|
data.addColumn('number', 'id');
|
|
data.addColumn('number', 'altitude');
|
|
var altLen = altitudes.length;
|
|
for (var i=0; i<altLen; i++) {
|
|
data.addRow([(i+1),Math.round((altitudes[i]*factor_m))]);
|
|
}
|
|
|
|
var options = {
|
|
title: lang_altitude+' ('+unit_m+')',
|
|
hAxis: { textPosition: 'none' },
|
|
legend: { position: 'none' }
|
|
};
|
|
|
|
chart = new google.visualization.LineChart(document.getElementById('chart'));
|
|
chart.draw(data, options);
|
|
|
|
google.visualization.events.addListener(chart, 'select', function() {
|
|
if (popup) {popup.close(); clearTimeout(altTimeout);}
|
|
var selection = chart.getSelection()[0];
|
|
if (selection) {
|
|
var id = selection.row;
|
|
var contentString = '<div style="width:40px; height:20px;padding:10px">'+Math.round(altitudes[id]*factor_m)+' '+unit_m+'</div>';
|
|
popup = new google.maps.InfoWindow({
|
|
content: contentString
|
|
});
|
|
popup.open(map,markers[id]);
|
|
altTimeout = setTimeout(function() { if (popup) {popup.close();} },2000);
|
|
}
|
|
});
|
|
}
|
|
|
|
function toggleChart(i) {
|
|
var altLen = altitudes.length;
|
|
if (altLen<=1) { return; }
|
|
var e = document.getElementById('bottom');
|
|
if (arguments.length < 1) {
|
|
if (e.style.display == 'block') { i = 0 }
|
|
else { i = 1; }
|
|
}
|
|
if (i==0) {
|
|
chart.clearChart();
|
|
e.style.display = 'none';
|
|
}
|
|
else {
|
|
e.style.display = 'block';
|
|
displayChart();
|
|
}
|
|
}
|
|
|
|
function getXHR() {
|
|
var xmlhttp = null;
|
|
if (window.XMLHttpRequest) {
|
|
xmlhttp=new XMLHttpRequest();
|
|
}
|
|
else {
|
|
xmlhttp=new ActiveXObject('Microsoft.XMLHTTP');
|
|
}
|
|
return xmlhttp;
|
|
}
|
|
|
|
function loadTrack(userid,trackid,update) {
|
|
if (latest==1) { trackid=0; }
|
|
var xhr = getXHR();
|
|
xhr.onreadystatechange = function() {
|
|
if (xhr.readyState==4 && xhr.status==200) {
|
|
var xml = xhr.responseXML;
|
|
var positions = xml.getElementsByTagName('position');
|
|
if (positions.length>0) {
|
|
clearMap();
|
|
displayTrack(xml,update);
|
|
}
|
|
xhr = null;
|
|
}
|
|
}
|
|
xhr.open('GET','getpositions.php?trackid='+trackid+'&userid='+userid,true);
|
|
xhr.send();
|
|
}
|
|
|
|
function parsePosition(p) {
|
|
// read data
|
|
var latitude = getNode(p,'latitude');
|
|
var longitude = getNode(p,'longitude');
|
|
var altitude = getNode(p,'altitude'); // may be null
|
|
if (altitude != null) { altitude = parseInt(altitude); }
|
|
var speed = getNode(p,'speed'); // may be null
|
|
if (speed != null) { speed = parseInt(speed); }
|
|
var angle = getNode(p,'angle'); // may be null
|
|
if (angle != null) { angle = parseInt(angle); }
|
|
var username = getNode(p,'username');
|
|
var trackname = getNode(p,'trackname');
|
|
var tid = getNode(p,'trackid');
|
|
var dateoccured = getNode(p,'dateoccured');
|
|
var distance = parseInt(getNode(p,'distance'));
|
|
var seconds = parseInt(getNode(p,'seconds'));
|
|
return {
|
|
'latitude': latitude,
|
|
'longitude': longitude,
|
|
'altitude': altitude,
|
|
'speed': speed,
|
|
'angle': angle,
|
|
'username': username,
|
|
'trackname': trackname,
|
|
'tid': tid,
|
|
'dateoccured': dateoccured,
|
|
'distance': distance,
|
|
'seconds': seconds
|
|
};
|
|
}
|
|
|
|
function load(type,userid,trackid) {
|
|
var url = 'download.php?type='+type+'&userid='+userid+'&trackid='+trackid;
|
|
window.location.assign(url);
|
|
}
|
|
|
|
function updateSummary(l,d,s) {
|
|
var t = document.getElementById('summary');
|
|
if (latest==0){
|
|
t.innerHTML = '<u>'+lang_summary+'</u><br />'+
|
|
lang_tdistance+': '+(d.toKm()*factor_km).toFixed(2)+' '+unit_km+'<br />'+
|
|
lang_ttime+': '+s.toHMS();
|
|
}
|
|
else {
|
|
t.innerHTML = '<u>'+lang_latest+':</u><br />'+l;
|
|
}
|
|
}
|
|
|
|
function getNode(p,name) {
|
|
return ((p.getElementsByTagName(name)[0].childNodes[0]) ? p.getElementsByTagName(name)[0].childNodes[0].nodeValue : null);
|
|
}
|
|
|
|
|
|
// seconds to (d) H:M:S
|
|
Number.prototype.toHMS = function(){
|
|
var s = this;
|
|
var d = Math.floor(s / 86400);
|
|
var h = Math.floor((s % 86400) / 3600);
|
|
var m = Math.floor(((s % 86400) % 3600) / 60);
|
|
s = ((s % 86400) % 3600) % 60;
|
|
|
|
return ((d>0)?(d + ' d '):'') + (('00'+h).slice(-2)) + ':' + (('00'+m).slice(-2)) + ':' + (('00'+s).slice(-2)) + '';
|
|
}
|
|
// meters to km
|
|
Number.prototype.toKm = function() {
|
|
return Math.round(this/10)/100;
|
|
}
|
|
// m/s to km/h
|
|
Number.prototype.toKmH = function() {
|
|
return Math.round(this*3600/10)/100;
|
|
}
|
|
|
|
// negate value
|
|
function toggleLatest() {
|
|
if (latest==0) {
|
|
latest = 1;
|
|
loadTrack(userid,0,1);
|
|
}
|
|
else {
|
|
latest = 0;
|
|
loadTrack(userid,trackid,1);
|
|
}
|
|
}
|
|
|
|
function setTrack(t) {
|
|
document.getElementsByName('track')[0].value = t;
|
|
}
|
|
|
|
function selectTrack(f) {
|
|
trackid=f.options[f.selectedIndex].value;
|
|
document.getElementById('latest').checked = false;
|
|
if (latest==1) { toggleLatest(); }
|
|
loadTrack(userid,trackid,1);
|
|
}
|
|
|
|
function selectUser(f) {
|
|
userid=f.options[f.selectedIndex].value;
|
|
if (f.options[0].disabled==false) {
|
|
f.options[0].disabled = true;
|
|
}
|
|
document.getElementById('latest').checked = false;
|
|
if (latest==1) { toggleLatest(); }
|
|
getTrips(userid);
|
|
}
|
|
|
|
function getTrips(userid) {
|
|
var xhr = getXHR();
|
|
xhr.onreadystatechange = function() {
|
|
if (xhr.readyState==4 && xhr.status==200) {
|
|
var xml = xhr.responseXML;
|
|
var trips = xml.getElementsByTagName('trip');
|
|
if (trips.length>0) {
|
|
fillOptions(xml);
|
|
}
|
|
xhr = null;
|
|
}
|
|
}
|
|
xhr.open('GET','gettrips.php?userid='+userid,true);
|
|
xhr.send();
|
|
}
|
|
|
|
function fillOptions(xml) {
|
|
var trackSelect = document.getElementsByName('track')[0];
|
|
clearOptions(trackSelect);
|
|
var trips = xml.getElementsByTagName('trip');
|
|
var trpLen = trips.length;
|
|
for (var i=0; i<trpLen; i++) {
|
|
var trackid = getNode(trips[i],'trackid');
|
|
var trackname = getNode(trips[i],'trackname');
|
|
var option = document.createElement("option");
|
|
option.value = trackid;
|
|
option.innerHTML = trackname;
|
|
trackSelect.appendChild(option);
|
|
}
|
|
var defaultTrack = getNode(trips[0],'trackid');
|
|
loadTrack(userid,defaultTrack,1);
|
|
}
|
|
|
|
function clearOptions(el){
|
|
if (el.options) {
|
|
while (el.options.length) {
|
|
el.remove(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
var auto;
|
|
function autoReload() {
|
|
if (live==0) {
|
|
live = 1;
|
|
auto = setInterval(function() { loadTrack(userid,trackid,0); },interval*1000);
|
|
}
|
|
else {
|
|
live = 0;
|
|
clearInterval(auto);
|
|
}
|
|
}
|
|
|
|
function setTime() {
|
|
var i = parseInt(prompt(lang_newinterval));
|
|
if (!isNaN(i) && i!=interval) {
|
|
interval = i;
|
|
document.getElementById('auto').innerHTML = interval;
|
|
// if live tracking on, reload with new interval
|
|
if (live==1) {
|
|
live = 0;
|
|
clearInterval(auto);
|
|
autoReload();
|
|
}
|
|
}
|
|
}
|