2017-01-30 21:36:44 +01:00
|
|
|
|
/* μlogger
|
2013-06-19 13:27:14 +02:00
|
|
|
|
*
|
2017-01-30 21:36:44 +01:00
|
|
|
|
* Copyright(C) 2017 Bartek Fabiszewski (www.fabiszewski.net)
|
2013-06-19 13:27:14 +02:00
|
|
|
|
*
|
|
|
|
|
* This is free software; you can redistribute it and/or modify it under
|
2017-04-07 00:05:28 +02:00
|
|
|
|
* the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2013-06-19 13:27:14 +02:00
|
|
|
|
* (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.
|
|
|
|
|
*
|
2017-04-07 00:05:28 +02:00
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
2013-06-19 13:27:14 +02:00
|
|
|
|
*/
|
2016-10-29 14:05:13 +02:00
|
|
|
|
|
2017-04-09 23:35:55 +02:00
|
|
|
|
// general stuff
|
2017-09-11 22:10:24 +02:00
|
|
|
|
var factor_kmh, unit_kmh, factor_m, unit_m, factor_km, unit_km;
|
2017-04-09 23:35:55 +02:00
|
|
|
|
if (units == 'imperial') {
|
2013-06-19 13:27:14 +02:00
|
|
|
|
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';
|
2017-05-10 14:54:38 +02:00
|
|
|
|
} else {
|
2013-06-19 13:27:14 +02:00
|
|
|
|
factor_kmh = 1;
|
|
|
|
|
unit_kmh = 'km/h';
|
|
|
|
|
factor_m = 1;
|
|
|
|
|
unit_m = 'm';
|
|
|
|
|
factor_km = 1;
|
|
|
|
|
unit_km = 'km';
|
|
|
|
|
}
|
|
|
|
|
var latest = 0;
|
|
|
|
|
var live = 0;
|
|
|
|
|
var chart;
|
2017-08-10 13:36:44 +02:00
|
|
|
|
var altitudes = {};
|
2013-06-19 13:27:14 +02:00
|
|
|
|
var altTimeout;
|
2017-05-05 09:14:46 +02:00
|
|
|
|
var gm_error = false;
|
2017-09-11 22:10:24 +02:00
|
|
|
|
var loadTime = 0;
|
|
|
|
|
var auto;
|
|
|
|
|
var savedBounds = null;
|
2017-05-05 09:14:46 +02:00
|
|
|
|
|
2013-06-19 13:27:14 +02:00
|
|
|
|
function displayChart() {
|
|
|
|
|
if (chart) { google.visualization.events.removeAllListeners(chart); }
|
|
|
|
|
var data = new google.visualization.DataTable();
|
|
|
|
|
data.addColumn('number', 'id');
|
2017-08-10 13:36:44 +02:00
|
|
|
|
data.addColumn('number', lang['altitude']);
|
|
|
|
|
|
|
|
|
|
for (var id in altitudes) {
|
|
|
|
|
if (altitudes.hasOwnProperty(id)) {
|
|
|
|
|
data.addRow([parseInt(id) + 1, Math.round((altitudes[id] * factor_m))]);
|
|
|
|
|
}
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var options = {
|
2017-04-09 23:35:55 +02:00
|
|
|
|
title: lang['altitude'] + ' (' + unit_m + ')',
|
2013-06-19 13:27:14 +02:00
|
|
|
|
hAxis: { textPosition: 'none' },
|
|
|
|
|
legend: { position: 'none' }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
chart = new google.visualization.LineChart(document.getElementById('chart'));
|
|
|
|
|
chart.draw(data, options);
|
2016-10-29 14:05:13 +02:00
|
|
|
|
|
2017-08-10 13:36:44 +02:00
|
|
|
|
addChartEvent(chart, data);
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function toggleChart(i) {
|
|
|
|
|
var altLen = altitudes.length;
|
2017-04-09 23:35:55 +02:00
|
|
|
|
if (altLen <= 1) { return; }
|
2013-06-19 13:27:14 +02:00
|
|
|
|
var e = document.getElementById('bottom');
|
|
|
|
|
if (arguments.length < 1) {
|
|
|
|
|
if (e.style.display == 'block') { i = 0 }
|
|
|
|
|
else { i = 1; }
|
2016-10-29 14:05:13 +02:00
|
|
|
|
}
|
2017-04-09 23:35:55 +02:00
|
|
|
|
if (i == 0) {
|
2013-06-19 13:27:14 +02:00
|
|
|
|
chart.clearChart();
|
|
|
|
|
e.style.display = 'none';
|
2017-05-23 11:32:50 +02:00
|
|
|
|
} else {
|
2013-06-19 13:27:14 +02:00
|
|
|
|
e.style.display = 'block';
|
|
|
|
|
displayChart();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-23 11:32:50 +02:00
|
|
|
|
function toggleChartLink() {
|
|
|
|
|
var link = document.getElementById('altitudes');
|
2017-08-10 13:36:44 +02:00
|
|
|
|
if (Object.keys(altitudes).length > 1) {
|
2017-05-23 11:32:50 +02:00
|
|
|
|
link.style.visibility = 'visible';
|
|
|
|
|
} else {
|
|
|
|
|
link.style.visibility = 'hidden';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-29 14:05:13 +02:00
|
|
|
|
function toggleMenu(i) {
|
2013-06-26 19:58:55 +02:00
|
|
|
|
var emenu = document.getElementById('menu');
|
|
|
|
|
var emain = document.getElementById('main');
|
|
|
|
|
var ebutton = document.getElementById('menu-close');
|
|
|
|
|
if (arguments.length < 1) {
|
|
|
|
|
if (ebutton.innerHTML == '»') { i = 0 }
|
|
|
|
|
else { i = 1; }
|
2016-10-29 14:05:13 +02:00
|
|
|
|
}
|
2017-04-09 23:35:55 +02:00
|
|
|
|
if (i == 0) {
|
2013-06-26 19:58:55 +02:00
|
|
|
|
emenu.style.width = '0';
|
|
|
|
|
emain.style.marginRight = '0';
|
|
|
|
|
ebutton.style.right = '0';
|
|
|
|
|
ebutton.innerHTML = '«';
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
emenu.style.width = '165px';
|
|
|
|
|
emain.style.marginRight = '165px';
|
|
|
|
|
ebutton.style.right = '165px';
|
|
|
|
|
ebutton.innerHTML = '»';
|
2016-10-29 14:05:13 +02:00
|
|
|
|
}
|
2013-06-26 19:58:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
2013-06-19 13:27:14 +02:00
|
|
|
|
function getXHR() {
|
|
|
|
|
var xmlhttp = null;
|
|
|
|
|
if (window.XMLHttpRequest) {
|
2017-04-09 23:35:55 +02:00
|
|
|
|
xmlhttp = new XMLHttpRequest();
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
|
|
|
|
else {
|
2017-04-09 23:35:55 +02:00
|
|
|
|
xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
|
|
|
|
return xmlhttp;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 23:35:55 +02:00
|
|
|
|
function loadTrack(userid, trackid, update) {
|
2017-05-10 14:54:38 +02:00
|
|
|
|
var title = document.getElementById("track").getElementsByClassName("menutitle")[0];
|
2017-04-14 17:24:09 +02:00
|
|
|
|
if (trackid < 0) { return; }
|
2017-04-09 23:35:55 +02:00
|
|
|
|
if (latest == 1) { trackid = 0; }
|
2013-06-19 13:27:14 +02:00
|
|
|
|
var xhr = getXHR();
|
2017-04-09 23:35:55 +02:00
|
|
|
|
xhr.onreadystatechange = function () {
|
2017-05-10 14:54:38 +02:00
|
|
|
|
if (xhr.readyState == 4) {
|
|
|
|
|
if (xhr.status == 200) {
|
|
|
|
|
var xml = xhr.responseXML;
|
|
|
|
|
var positions = xml.getElementsByTagName('position');
|
|
|
|
|
if (positions.length > 0) {
|
|
|
|
|
clearMap();
|
|
|
|
|
displayTrack(xml, update);
|
2017-05-23 11:32:50 +02:00
|
|
|
|
toggleChartLink();
|
2017-05-10 14:54:38 +02:00
|
|
|
|
}
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
|
|
|
|
xhr = null;
|
2017-05-10 14:54:38 +02:00
|
|
|
|
removeLoader(title);
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-04-11 17:00:40 +02:00
|
|
|
|
xhr.open('GET', 'utils/getpositions.php?trackid=' + trackid + '&userid=' + userid, true);
|
2013-06-19 13:27:14 +02:00
|
|
|
|
xhr.send();
|
2017-05-10 14:54:38 +02:00
|
|
|
|
setLoader(title);
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-10 13:36:44 +02:00
|
|
|
|
function parsePosition(p, id) {
|
2017-04-09 23:35:55 +02:00
|
|
|
|
// read data
|
2017-09-11 22:10:24 +02:00
|
|
|
|
var latitude = parseFloat(getNode(p, 'latitude'));
|
|
|
|
|
var longitude = parseFloat(getNode(p, 'longitude'));
|
2017-04-09 23:35:55 +02:00
|
|
|
|
var altitude = getNode(p, 'altitude'); // may be null
|
2017-05-23 11:32:50 +02:00
|
|
|
|
if (altitude != null) {
|
|
|
|
|
altitude = parseInt(altitude);
|
|
|
|
|
// save altitudes for chart
|
2017-08-10 13:36:44 +02:00
|
|
|
|
altitudes[id] = altitude;
|
2017-05-23 11:32:50 +02:00
|
|
|
|
}
|
2017-04-09 23:35:55 +02:00
|
|
|
|
var speed = getNode(p, 'speed'); // may be null
|
2013-06-19 13:27:14 +02:00
|
|
|
|
if (speed != null) { speed = parseInt(speed); }
|
2017-04-09 23:35:55 +02:00
|
|
|
|
var bearing = getNode(p, 'bearing'); // may be null
|
2017-01-30 23:46:25 +01:00
|
|
|
|
if (bearing != null) { bearing = parseInt(bearing); }
|
2017-04-09 23:35:55 +02:00
|
|
|
|
var accuracy = getNode(p, 'accuracy'); // may be null
|
2017-01-30 21:36:44 +01:00
|
|
|
|
if (accuracy != null) { accuracy = parseInt(accuracy); }
|
2017-04-09 23:35:55 +02:00
|
|
|
|
var provider = getNode(p, 'provider'); // may be null
|
|
|
|
|
var comments = getNode(p, 'comments'); // may be null
|
|
|
|
|
var username = getNode(p, 'username');
|
|
|
|
|
var trackname = getNode(p, 'trackname');
|
|
|
|
|
var tid = getNode(p, 'trackid');
|
2017-05-22 13:39:40 +02:00
|
|
|
|
var timestamp = getNode(p, 'timestamp');
|
2017-04-09 23:35:55 +02:00
|
|
|
|
var distance = parseInt(getNode(p, 'distance'));
|
|
|
|
|
var seconds = parseInt(getNode(p, 'seconds'));
|
2013-06-19 13:27:14 +02:00
|
|
|
|
return {
|
|
|
|
|
'latitude': latitude,
|
|
|
|
|
'longitude': longitude,
|
|
|
|
|
'altitude': altitude,
|
|
|
|
|
'speed': speed,
|
2017-01-30 23:46:25 +01:00
|
|
|
|
'bearing': bearing,
|
2017-01-30 21:36:44 +01:00
|
|
|
|
'accuracy': accuracy,
|
2017-04-09 14:03:43 +02:00
|
|
|
|
'provider': provider,
|
2013-07-25 23:34:13 +02:00
|
|
|
|
'comments': comments,
|
2013-06-19 13:27:14 +02:00
|
|
|
|
'username': username,
|
|
|
|
|
'trackname': trackname,
|
|
|
|
|
'tid': tid,
|
2017-05-22 13:39:40 +02:00
|
|
|
|
'timestamp': timestamp,
|
2013-06-19 13:27:14 +02:00
|
|
|
|
'distance': distance,
|
|
|
|
|
'seconds': seconds
|
2016-10-29 14:05:13 +02:00
|
|
|
|
};
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 14:03:43 +02:00
|
|
|
|
function getPopupHtml(p, i, count) {
|
2017-05-22 13:39:40 +02:00
|
|
|
|
var date = '–––';
|
|
|
|
|
var time = '–––';
|
|
|
|
|
if (p.timestamp > 0) {
|
|
|
|
|
var d = new Date(p.timestamp * 1000);
|
|
|
|
|
date = d.getFullYear() + '-' + ('0' + (d.getMonth() + 1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2);
|
|
|
|
|
time = d.toTimeString();
|
|
|
|
|
var offset;
|
|
|
|
|
if ((offset = time.indexOf(' ')) >= 0) {
|
|
|
|
|
time = time.substr(0, offset) + ' <span class="smaller">' + time.substr(offset + 1) + '</span>';
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-04-09 14:03:43 +02:00
|
|
|
|
var provider = '';
|
|
|
|
|
if (p.provider == 'gps') {
|
2017-04-10 22:46:56 +02:00
|
|
|
|
provider = ' (<img class="icon" alt="' + lang['gps'] + '" title="' + lang['gps'] + '" src="images/gps_dark.svg">)';
|
2017-04-09 14:03:43 +02:00
|
|
|
|
} else if (p.provider == 'network') {
|
2017-04-10 22:46:56 +02:00
|
|
|
|
provider = ' (<img class="icon" alt="' + lang['network'] + '" title="' + lang['network'] + '" src="images/network_dark.svg">)';
|
2017-04-09 23:35:55 +02:00
|
|
|
|
}
|
|
|
|
|
var stats = '';
|
|
|
|
|
if (latest == 0) {
|
|
|
|
|
stats =
|
|
|
|
|
'<div id="pright">' +
|
2017-04-10 22:46:56 +02:00
|
|
|
|
'<img class="icon" alt="' + lang['track'] + '" src="images/stats_blue.svg" style="padding-left: 3em;"><br>' +
|
|
|
|
|
'<img class="icon" alt="' + lang['ttime'] + '" title="' + lang['ttime'] + '" src="images/time_blue.svg"> ' +
|
|
|
|
|
p.totalSeconds.toHMS() + '<br>' +
|
|
|
|
|
'<img class="icon" alt="' + lang['aspeed'] + '" title="' + lang['aspeed'] + '" src="images/speed_blue.svg"> ' +
|
|
|
|
|
((p.totalSeconds > 0) ? ((p.totalMeters / p.totalSeconds).toKmH() * factor_kmh).toFixed() : 0) + ' ' + unit_kmh + '<br>' +
|
|
|
|
|
'<img class="icon" alt="' + lang['tdistance'] + '" title="' + lang['tdistance'] + '" src="images/distance_blue.svg"> ' +
|
|
|
|
|
(p.totalMeters.toKm() * factor_km).toFixed(2) + ' ' + unit_km + '<br>' + '</div>';
|
2017-04-09 23:35:55 +02:00
|
|
|
|
}
|
2017-09-11 22:10:24 +02:00
|
|
|
|
var popup =
|
2017-04-09 23:35:55 +02:00
|
|
|
|
'<div id="popup">' +
|
|
|
|
|
'<div id="pheader">' +
|
2017-04-14 16:00:53 +02:00
|
|
|
|
'<div><img alt="' + lang['user'] + '" title="' + lang['user'] + '" src="images/user_dark.svg"> ' + htmlEncode(p.username) + '</div>' +
|
|
|
|
|
'<div><img alt="' + lang['track'] + '" title="' + lang['track'] + '" src="images/route_dark.svg"> ' + htmlEncode(p.trackname) + '</div>' +
|
2017-04-09 23:35:55 +02:00
|
|
|
|
'</div>' +
|
|
|
|
|
'<div id="pbody">' +
|
2017-04-14 16:00:53 +02:00
|
|
|
|
((p.comments != null) ? '<div id="pcomments">' + htmlEncode(p.comments) + '</div>' : '') +
|
2017-04-09 23:35:55 +02:00
|
|
|
|
'<div id="pleft">' +
|
2017-04-10 22:46:56 +02:00
|
|
|
|
'<img class="icon" alt="' + lang['time'] + '" title="' + lang['time'] + '" src="images/calendar_dark.svg"> ' + date + '<br>' +
|
|
|
|
|
'<img class="icon" alt="' + lang['time'] + '" title="' + lang['time'] + '" src="images/clock_dark.svg"> ' + time + '<br>' +
|
|
|
|
|
((p.speed != null) ? '<img class="icon" alt="' + lang['speed'] + '" title="' + lang['speed'] + '" src="images/speed_dark.svg"> ' +
|
|
|
|
|
(p.speed.toKmH() * factor_kmh) + ' ' + unit_kmh + '<br>' : '') +
|
|
|
|
|
((p.altitude != null) ? '<img class="icon" alt="' + lang['altitude'] + '" title="' + lang['altitude'] + '" src="images/altitude_dark.svg"> ' +
|
|
|
|
|
(p.altitude * factor_m).toFixed() + ' ' + unit_m + '<br>' : '') +
|
|
|
|
|
((p.accuracy != null) ? '<img class="icon" alt="' + lang['accuracy'] + '" title="' + lang['accuracy'] + '" src="images/accuracy_dark.svg"> ' +
|
|
|
|
|
(p.accuracy * factor_m).toFixed() + ' ' + unit_m + provider + '<br>' : '') +
|
2017-04-09 23:35:55 +02:00
|
|
|
|
'</div>' +
|
|
|
|
|
stats +
|
2017-04-15 13:41:21 +02:00
|
|
|
|
'</div><div id="pfooter">' + sprintf(lang['pointof'], i + 1, count) + '</div>' +
|
2017-04-12 21:48:40 +02:00
|
|
|
|
'</div>';
|
2017-04-09 14:03:43 +02:00
|
|
|
|
return popup;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-09 09:06:23 +02:00
|
|
|
|
function exportFile(type, userid, trackid) {
|
|
|
|
|
var url = 'utils/export.php?type=' + type + '&userid=' + userid + '&trackid=' + trackid;
|
2013-06-19 13:27:14 +02:00
|
|
|
|
window.location.assign(url);
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-09 22:48:17 +02:00
|
|
|
|
function importFile(input) {
|
|
|
|
|
var form = input.parentElement;
|
2017-05-10 14:54:38 +02:00
|
|
|
|
var title = form.parentElement.getElementsByClassName("menutitle")[0];
|
2017-05-09 22:48:17 +02:00
|
|
|
|
var sizeMax = form.elements['MAX_FILE_SIZE'].value;
|
|
|
|
|
if (input.files && input.files.length == 1 && input.files[0].size > sizeMax) {
|
|
|
|
|
alert(sprintf(lang['isizefailure'], sizeMax));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-05-09 09:06:23 +02:00
|
|
|
|
var xhr = getXHR();
|
|
|
|
|
xhr.onreadystatechange = function() {
|
2017-05-10 14:54:38 +02:00
|
|
|
|
if (xhr.readyState == 4) {
|
|
|
|
|
var error = true;
|
2017-05-09 09:06:23 +02:00
|
|
|
|
var message = "";
|
2017-05-10 14:54:38 +02:00
|
|
|
|
if (xhr.status == 200) {
|
|
|
|
|
var xml = xhr.responseXML;
|
|
|
|
|
if (xml) {
|
|
|
|
|
var root = xml.getElementsByTagName('root');
|
|
|
|
|
if (root.length && getNode(root[0], 'error') == 0) {
|
|
|
|
|
trackId = getNode(root[0], 'trackid');
|
|
|
|
|
trackCnt = getNode(root[0], 'trackcnt');
|
|
|
|
|
getTracks(userid, trackId);
|
|
|
|
|
if (trackCnt > 1) {
|
|
|
|
|
alert(sprintf(lang['imultiple'], trackCnt));
|
|
|
|
|
}
|
|
|
|
|
error = false;
|
|
|
|
|
} else if (root.length) {
|
|
|
|
|
errorMsg = getNode(root[0], 'message');
|
|
|
|
|
if (errorMsg) { message = errorMsg; }
|
2017-05-09 16:00:02 +02:00
|
|
|
|
}
|
2017-05-09 09:06:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-10 14:54:38 +02:00
|
|
|
|
if (error) {
|
|
|
|
|
alert(lang['actionfailure'] + '\n' + message);
|
|
|
|
|
}
|
|
|
|
|
removeLoader(title);
|
2017-05-09 09:06:23 +02:00
|
|
|
|
xhr = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
xhr.open("POST", "utils/import.php", true);
|
2017-05-09 22:48:17 +02:00
|
|
|
|
xhr.send(new FormData(form));
|
2017-05-09 18:41:53 +02:00
|
|
|
|
input.value = "";
|
2017-05-10 14:54:38 +02:00
|
|
|
|
setLoader(title);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setLoader(el) {
|
|
|
|
|
var s = el.textContent || el.innerText;
|
|
|
|
|
var newHTML = '';
|
|
|
|
|
for (var i = 0, len = s.length; i < len; i++) {
|
|
|
|
|
newHTML += '<span class="loader">' + s.charAt(i) + '</span>';
|
|
|
|
|
}
|
|
|
|
|
el.innerHTML = newHTML;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function removeLoader(el) {
|
|
|
|
|
el.innerHTML = el.textContent || el.innerText;
|
2017-05-09 09:06:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-22 13:39:40 +02:00
|
|
|
|
function updateSummary(timestamp, d, s) {
|
2013-06-19 13:27:14 +02:00
|
|
|
|
var t = document.getElementById('summary');
|
2017-04-09 23:35:55 +02:00
|
|
|
|
if (latest == 0) {
|
2017-05-10 14:54:38 +02:00
|
|
|
|
t.innerHTML = '<div class="menutitle u">' + lang['summary'] + '</div>' +
|
2017-05-22 13:39:40 +02:00
|
|
|
|
'<div><img class="icon" alt="' + lang['tdistance'] + '" title="' + lang['tdistance'] + '" src="images/distance.svg"> ' + (d.toKm() * factor_km).toFixed(2) + ' ' + unit_km + '</div>' +
|
|
|
|
|
'<div><img class="icon" alt="' + lang['ttime'] + '" title="' + lang['ttime'] + '" src="images/time.svg"> ' + s.toHMS() + '</div>';
|
|
|
|
|
} else {
|
|
|
|
|
var today = new Date();
|
|
|
|
|
var d = new Date(timestamp * 1000);
|
|
|
|
|
var dateString = '';
|
|
|
|
|
if (d.toDateString() != today.toDateString()) {
|
|
|
|
|
dateString += d.getFullYear() + '-' + ('0' + (d.getMonth() + 1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2);
|
|
|
|
|
dateString += '<br>';
|
|
|
|
|
}
|
|
|
|
|
var timeString = d.toTimeString();
|
|
|
|
|
var offset;
|
|
|
|
|
if ((offset = timeString.indexOf(' ')) >= 0) {
|
|
|
|
|
timeString = timeString.substr(0, offset) + ' <span style="font-weight:normal">' + timeString.substr(offset + 1) + '</span>';
|
|
|
|
|
}
|
|
|
|
|
t.innerHTML = '<div class="menutitle u">' + lang['latest'] + ':</div>' + dateString + timeString;
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 23:35:55 +02:00
|
|
|
|
function getNode(p, name) {
|
2013-06-19 13:27:14 +02:00
|
|
|
|
return ((p.getElementsByTagName(name)[0].childNodes[0]) ? p.getElementsByTagName(name)[0].childNodes[0].nodeValue : null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// seconds to (d) H:M:S
|
2017-04-12 20:16:39 +02:00
|
|
|
|
Number.prototype.toHMS = function() {
|
2013-06-19 13:27:14 +02:00
|
|
|
|
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;
|
|
|
|
|
|
2017-04-09 23:35:55 +02:00
|
|
|
|
return ((d > 0) ? (d + ' d ') : '') + (('00' + h).slice(-2)) + ':' + (('00' + m).slice(-2)) + ':' + (('00' + s).slice(-2)) + '';
|
2017-04-12 20:16:39 +02:00
|
|
|
|
};
|
2017-04-09 23:35:55 +02:00
|
|
|
|
|
2013-06-19 13:27:14 +02:00
|
|
|
|
// meters to km
|
2017-04-12 20:16:39 +02:00
|
|
|
|
Number.prototype.toKm = function() {
|
2017-04-09 23:35:55 +02:00
|
|
|
|
return Math.round(this / 10) / 100;
|
2017-04-12 20:16:39 +02:00
|
|
|
|
};
|
2017-04-09 23:35:55 +02:00
|
|
|
|
|
2013-06-19 13:27:14 +02:00
|
|
|
|
// m/s to km/h
|
2017-04-12 20:16:39 +02:00
|
|
|
|
Number.prototype.toKmH = function() {
|
2017-04-09 23:35:55 +02:00
|
|
|
|
return Math.round(this * 3600 / 10) / 100;
|
2017-04-12 20:16:39 +02:00
|
|
|
|
};
|
2013-06-19 13:27:14 +02:00
|
|
|
|
|
|
|
|
|
// negate value
|
|
|
|
|
function toggleLatest() {
|
2017-04-09 23:35:55 +02:00
|
|
|
|
if (latest == 0) {
|
2013-06-19 13:27:14 +02:00
|
|
|
|
latest = 1;
|
2017-04-09 23:35:55 +02:00
|
|
|
|
loadTrack(userid, 0, 1);
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
latest = 0;
|
2017-04-09 23:35:55 +02:00
|
|
|
|
loadTrack(userid, trackid, 1);
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setTrack(t) {
|
|
|
|
|
document.getElementsByName('track')[0].value = t;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function selectTrack(f) {
|
2017-04-14 17:24:09 +02:00
|
|
|
|
if (f.selectedIndex >= 0) {
|
|
|
|
|
trackid = f.options[f.selectedIndex].value;
|
|
|
|
|
} else {
|
|
|
|
|
trackid = 0;
|
|
|
|
|
}
|
2013-06-19 13:27:14 +02:00
|
|
|
|
document.getElementById('latest').checked = false;
|
2017-04-09 23:35:55 +02:00
|
|
|
|
if (latest == 1) { toggleLatest(); }
|
|
|
|
|
loadTrack(userid, trackid, 1);
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function selectUser(f) {
|
2017-04-09 23:35:55 +02:00
|
|
|
|
userid = f.options[f.selectedIndex].value;
|
|
|
|
|
if (f.options[0].disabled == false) {
|
2013-06-19 13:27:14 +02:00
|
|
|
|
f.options[0].disabled = true;
|
|
|
|
|
}
|
|
|
|
|
document.getElementById('latest').checked = false;
|
2017-04-09 23:35:55 +02:00
|
|
|
|
if (latest == 1) { toggleLatest(); }
|
2017-01-30 21:36:44 +01:00
|
|
|
|
getTracks(userid);
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-10 14:54:38 +02:00
|
|
|
|
function getTracks(userid, trackid) {
|
|
|
|
|
var title = document.getElementById("track").getElementsByClassName("menutitle")[0];
|
2013-06-19 13:27:14 +02:00
|
|
|
|
var xhr = getXHR();
|
2017-04-09 23:35:55 +02:00
|
|
|
|
xhr.onreadystatechange = function () {
|
2017-05-10 14:54:38 +02:00
|
|
|
|
if (xhr.readyState == 4) {
|
|
|
|
|
if (xhr.status == 200) {
|
|
|
|
|
var xml = xhr.responseXML;
|
|
|
|
|
var trackSelect = document.getElementsByName('track')[0];
|
|
|
|
|
clearOptions(trackSelect);
|
|
|
|
|
var tracks = xml.getElementsByTagName('track');
|
|
|
|
|
if (tracks.length > 0) {
|
|
|
|
|
fillOptions(xml, userid, trackid);
|
|
|
|
|
} else {
|
|
|
|
|
clearMap();
|
|
|
|
|
}
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
2017-05-10 14:54:38 +02:00
|
|
|
|
removeLoader(title);
|
2013-06-19 13:27:14 +02:00
|
|
|
|
xhr = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-04-11 17:00:40 +02:00
|
|
|
|
xhr.open('GET', 'utils/gettracks.php?userid=' + userid, true);
|
2016-10-29 14:05:13 +02:00
|
|
|
|
xhr.send();
|
2017-05-10 14:54:38 +02:00
|
|
|
|
setLoader(title);
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-10 14:54:38 +02:00
|
|
|
|
function fillOptions(xml, uid, tid) {
|
2017-04-09 23:35:55 +02:00
|
|
|
|
var trackSelect = document.getElementsByName('track')[0];
|
2017-01-30 21:36:44 +01:00
|
|
|
|
var tracks = xml.getElementsByTagName('track');
|
|
|
|
|
var trackLen = tracks.length;
|
2017-04-09 23:35:55 +02:00
|
|
|
|
for (var i = 0; i < trackLen; i++) {
|
|
|
|
|
var trackid = getNode(tracks[i], 'trackid');
|
|
|
|
|
var trackname = getNode(tracks[i], 'trackname');
|
2013-06-19 13:27:14 +02:00
|
|
|
|
var option = document.createElement("option");
|
|
|
|
|
option.value = trackid;
|
2017-04-14 16:00:53 +02:00
|
|
|
|
option.innerHTML = htmlEncode(trackname);
|
2013-06-19 13:27:14 +02:00
|
|
|
|
trackSelect.appendChild(option);
|
2016-10-29 14:05:13 +02:00
|
|
|
|
}
|
2017-05-10 14:54:38 +02:00
|
|
|
|
var defaultTrack = tid || getNode(tracks[0], 'trackid');
|
|
|
|
|
var defaultUser = uid || userid;
|
|
|
|
|
loadTrack(defaultUser, defaultTrack, 1);
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-09 23:35:55 +02:00
|
|
|
|
function clearOptions(el) {
|
2013-06-19 13:27:14 +02:00
|
|
|
|
if (el.options) {
|
|
|
|
|
while (el.options.length) {
|
|
|
|
|
el.remove(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function autoReload() {
|
2017-04-09 23:35:55 +02:00
|
|
|
|
if (live == 0) {
|
2013-06-19 13:27:14 +02:00
|
|
|
|
live = 1;
|
2017-04-09 23:35:55 +02:00
|
|
|
|
auto = setInterval(function () { loadTrack(userid, trackid, 0); }, interval * 1000);
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
live = 0;
|
|
|
|
|
clearInterval(auto);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setTime() {
|
2017-04-07 18:37:17 +02:00
|
|
|
|
var i = parseInt(prompt(lang['newinterval']));
|
2017-04-09 23:35:55 +02:00
|
|
|
|
if (!isNaN(i) && i != interval) {
|
2013-06-19 13:27:14 +02:00
|
|
|
|
interval = i;
|
|
|
|
|
document.getElementById('auto').innerHTML = interval;
|
|
|
|
|
// if live tracking on, reload with new interval
|
2017-04-09 23:35:55 +02:00
|
|
|
|
if (live == 1) {
|
2013-06-19 13:27:14 +02:00
|
|
|
|
live = 0;
|
|
|
|
|
clearInterval(auto);
|
|
|
|
|
autoReload();
|
|
|
|
|
}
|
2017-04-09 23:35:55 +02:00
|
|
|
|
// save current state as default
|
|
|
|
|
setCookie('interval', interval, 30);
|
2016-10-29 14:05:13 +02:00
|
|
|
|
}
|
2013-06-21 11:15:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// dynamic change of map api
|
|
|
|
|
function loadMapAPI(api) {
|
2017-09-11 22:10:24 +02:00
|
|
|
|
if (api) {
|
|
|
|
|
mapapi = api;
|
|
|
|
|
try {
|
|
|
|
|
savedBounds = getBounds();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
savedBounds = null;
|
|
|
|
|
}
|
|
|
|
|
cleanup();
|
|
|
|
|
}
|
|
|
|
|
removeElementById('mapapi');
|
|
|
|
|
var urls = [];
|
|
|
|
|
if (mapapi == 'gmaps') {
|
|
|
|
|
addScript('js/api_gmaps.js', 'mapapi');
|
|
|
|
|
urls.push('//maps.googleapis.com/maps/api/js?' + ((gkey !== null) ? ('key=' + gkey + '&') : '') + 'callback=init');
|
|
|
|
|
} else if (mapapi == 'openlayers') {
|
|
|
|
|
addScript('js/api_openlayers.js', 'mapapi');
|
|
|
|
|
urls.push('//openlayers.org/api/OpenLayers.js');
|
|
|
|
|
} else {
|
|
|
|
|
addScript('js/api_openlayers3.js', 'mapapi');
|
|
|
|
|
urls.push('//cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList')
|
|
|
|
|
urls.push('//openlayers.org/en/v4.3.2/build/ol.js');
|
2016-10-29 14:05:13 +02:00
|
|
|
|
}
|
2017-09-11 22:10:24 +02:00
|
|
|
|
waitAndLoad(mapapi, urls);
|
2013-06-21 11:15:09 +02:00
|
|
|
|
}
|
2017-04-09 23:35:55 +02:00
|
|
|
|
|
2017-09-11 22:10:24 +02:00
|
|
|
|
function waitAndLoad(api, urls) {
|
2016-10-29 14:05:13 +02:00
|
|
|
|
// wait till first script loaded
|
2017-04-12 22:42:23 +02:00
|
|
|
|
if (loadTime > 5000) { loadTime = 0; alert(sprintf(lang['apifailure'], api)); return; }
|
2017-09-11 22:10:24 +02:00
|
|
|
|
if (typeof loadedAPI === 'undefined' || loadedAPI !== api) {
|
|
|
|
|
setTimeout(function () { loadTime += 50; waitAndLoad(api, urls); }, 50);
|
2016-10-29 14:05:13 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-09-11 22:10:24 +02:00
|
|
|
|
for (var i = 0; i < urls.length; i++) {
|
|
|
|
|
addScript(urls[i], 'mapapi_' + api + '_' + i);
|
2016-10-29 14:05:13 +02:00
|
|
|
|
}
|
|
|
|
|
loadTime = 0;
|
|
|
|
|
waitAndInit(api);
|
2013-06-21 11:15:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function waitAndInit(api) {
|
2016-10-29 14:05:13 +02:00
|
|
|
|
// wait till main api loads
|
2017-04-12 22:42:23 +02:00
|
|
|
|
if (loadTime > 10000) { loadTime = 0; alert(sprintf(lang['apifailure'], api)); return; }
|
2016-10-29 14:05:13 +02:00
|
|
|
|
try {
|
|
|
|
|
init();
|
2017-09-11 22:10:24 +02:00
|
|
|
|
} catch (e) {
|
2017-04-09 23:35:55 +02:00
|
|
|
|
setTimeout(function () { loadTime += 50; waitAndInit(api); }, 50);
|
2016-10-29 14:05:13 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
loadTime = 0;
|
2017-05-05 09:14:46 +02:00
|
|
|
|
var update = 1;
|
|
|
|
|
if (savedBounds) {
|
|
|
|
|
zoomToBounds(savedBounds);
|
|
|
|
|
update = 0;
|
|
|
|
|
}
|
|
|
|
|
loadTrack(userid, trackid, update);
|
2016-10-29 14:05:13 +02:00
|
|
|
|
// save current api as default
|
2017-04-09 23:35:55 +02:00
|
|
|
|
setCookie('api', api, 30);
|
2013-06-21 11:15:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-11 22:10:24 +02:00
|
|
|
|
function addScript(url, id) {
|
|
|
|
|
if (id && document.getElementById(id)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-10-29 14:05:13 +02:00
|
|
|
|
var tag = document.createElement('script');
|
2017-09-11 22:10:24 +02:00
|
|
|
|
tag.type = 'text/javascript';
|
|
|
|
|
tag.src = url;
|
|
|
|
|
if (id) {
|
|
|
|
|
tag.id = id;
|
|
|
|
|
}
|
|
|
|
|
document.getElementsByTagName('head')[0].appendChild(tag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function addCss(url, id) {
|
|
|
|
|
if (id && document.getElementById(id)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var tag = document.createElement('link');
|
|
|
|
|
tag.type = 'text/css';
|
|
|
|
|
tag.rel = 'stylesheet';
|
|
|
|
|
tag.href = url;
|
|
|
|
|
if (id) {
|
|
|
|
|
tag.id = id;
|
|
|
|
|
}
|
2017-09-06 22:12:23 +02:00
|
|
|
|
document.getElementsByTagName('head')[0].appendChild(tag);
|
2013-06-21 11:15:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-11 22:10:24 +02:00
|
|
|
|
function removeElementById(id) {
|
|
|
|
|
var tag = document.getElementById(id);
|
|
|
|
|
if (tag && tag.parentNode) {
|
|
|
|
|
tag.parentNode.removeChild(tag);
|
2016-10-29 14:05:13 +02:00
|
|
|
|
}
|
2013-06-19 13:27:14 +02:00
|
|
|
|
}
|
2013-06-23 23:43:09 +02:00
|
|
|
|
|
2017-04-09 23:35:55 +02:00
|
|
|
|
function setCookie(name, value, days) {
|
2016-10-29 14:05:13 +02:00
|
|
|
|
if (days) {
|
2013-06-23 23:43:09 +02:00
|
|
|
|
var date = new Date();
|
2017-04-09 23:35:55 +02:00
|
|
|
|
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
|
|
|
|
var expires = '; expires=' + date.toGMTString();
|
2017-09-11 22:10:24 +02:00
|
|
|
|
} else {
|
2016-10-29 14:05:13 +02:00
|
|
|
|
var expires = '';
|
|
|
|
|
}
|
2017-04-09 23:35:55 +02:00
|
|
|
|
document.cookie = 'ulogger_' + name + '=' + value + expires + '; path=/';
|
2013-06-23 23:43:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setLang(lang) {
|
2017-04-09 23:35:55 +02:00
|
|
|
|
setCookie('lang', lang, 30);
|
2013-06-23 23:43:09 +02:00
|
|
|
|
location.reload();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setUnits(unit) {
|
|
|
|
|
units = unit;
|
2017-04-09 23:35:55 +02:00
|
|
|
|
setCookie('units', unit, 30);
|
2013-06-23 23:43:09 +02:00
|
|
|
|
location.reload();
|
|
|
|
|
}
|
2017-04-06 18:07:15 +02:00
|
|
|
|
|
|
|
|
|
function showModal(contentHTML) {
|
2017-04-06 23:23:25 +02:00
|
|
|
|
var div = document.createElement('div');
|
|
|
|
|
div.setAttribute('id', 'modal');
|
2017-04-10 22:46:56 +02:00
|
|
|
|
div.innerHTML = '<div id="modal-header"><button type="button" onclick="removeModal()"><img alt="' + lang['close'] + '" src="images/close.svg"></button></div><div id="modal-body"></div>';
|
2017-04-06 18:07:15 +02:00
|
|
|
|
document.body.appendChild(div);
|
|
|
|
|
var modalBody = document.getElementById('modal-body');
|
|
|
|
|
modalBody.innerHTML = contentHTML;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function removeModal() {
|
|
|
|
|
document.body.removeChild(document.getElementById('modal'));
|
2017-04-06 23:23:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function userMenu() {
|
|
|
|
|
var dropdown = document.getElementById('user_dropdown');
|
|
|
|
|
if (dropdown.classList.contains('show')) {
|
|
|
|
|
dropdown.classList.remove('show');
|
|
|
|
|
} else {
|
|
|
|
|
dropdown.classList.add('show');
|
|
|
|
|
window.addEventListener('click', removeOnClick, true);
|
2017-04-09 23:35:55 +02:00
|
|
|
|
}
|
2017-04-06 23:23:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function removeOnClick(event) {
|
|
|
|
|
var parent = event.target.parentElement;
|
|
|
|
|
var dropdown = document.getElementById('user_dropdown');
|
|
|
|
|
dropdown.classList.remove('show');
|
|
|
|
|
window.removeEventListener('click', removeOnClick, true);
|
|
|
|
|
if (!parent.classList.contains('dropdown')) {
|
|
|
|
|
event.stopPropagation();
|
|
|
|
|
}
|
2017-04-12 21:48:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// naive approach, only %s, %d supported
|
|
|
|
|
function sprintf() {
|
|
|
|
|
var args = Array.prototype.slice.call(arguments);
|
|
|
|
|
var format = args.shift();
|
|
|
|
|
var i = 0;
|
|
|
|
|
return format.replace(/%%|%s|%d/g, function(match) {
|
|
|
|
|
if (match == '%%') { return '%'; }
|
|
|
|
|
return (typeof args[i] != 'undefined') ? args[i++] : match;
|
|
|
|
|
});
|
2017-04-14 16:00:53 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function htmlEncode(s) {
|
|
|
|
|
return s.replace(/&/g, '&')
|
|
|
|
|
.replace(/"/g, '"')
|
|
|
|
|
.replace(/'/g, ''')
|
|
|
|
|
.replace(/</g, '<')
|
|
|
|
|
.replace(/>/g, '>');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!String.prototype.trim) {
|
|
|
|
|
String.prototype.trim = function () {
|
|
|
|
|
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
|
|
|
|
|
};
|
|
|
|
|
}
|