Add track class
This commit is contained in:
parent
b109547901
commit
d3b1fa8937
@ -32,7 +32,7 @@
|
|||||||
$upload_max_filesize = self::iniGetBytes('upload_max_filesize');
|
$upload_max_filesize = self::iniGetBytes('upload_max_filesize');
|
||||||
$post_max_size = self::iniGetBytes('post_max_size');
|
$post_max_size = self::iniGetBytes('post_max_size');
|
||||||
// post_max_size = 0 means unlimited size
|
// post_max_size = 0 means unlimited size
|
||||||
if ($post_max_size == 0) { $post_max_size = $upload_max_filesize; }
|
if ($post_max_size === 0) { $post_max_size = $upload_max_filesize; }
|
||||||
$memory_limit = self::iniGetBytes('memory_limit');
|
$memory_limit = self::iniGetBytes('memory_limit');
|
||||||
// memory_limit = -1 means no limit
|
// memory_limit = -1 means no limit
|
||||||
if ($memory_limit < 0) { $memory_limit = $post_max_size; }
|
if ($memory_limit < 0) { $memory_limit = $post_max_size; }
|
||||||
@ -45,10 +45,11 @@
|
|||||||
*
|
*
|
||||||
* @param string $iniParam Ini parameter name
|
* @param string $iniParam Ini parameter name
|
||||||
* @return int Bytes
|
* @return int Bytes
|
||||||
|
* @noinspection PhpMissingBreakStatementInspection
|
||||||
*/
|
*/
|
||||||
private static function iniGetBytes($iniParam) {
|
private static function iniGetBytes($iniParam) {
|
||||||
$iniStr = ini_get($iniParam);
|
$iniStr = ini_get($iniParam);
|
||||||
$val = floatval($iniStr);
|
$val = (float) $iniStr;
|
||||||
$suffix = substr(trim($iniStr), -1);
|
$suffix = substr(trim($iniStr), -1);
|
||||||
if (ctype_alpha($suffix)) {
|
if (ctype_alpha($suffix)) {
|
||||||
switch (strtolower($suffix)) {
|
switch (strtolower($suffix)) {
|
||||||
@ -89,22 +90,15 @@
|
|||||||
* @param array|null $extra Optional array of extra parameters
|
* @param array|null $extra Optional array of extra parameters
|
||||||
*/
|
*/
|
||||||
private static function exitWithStatus($isError, $extra = NULL) {
|
private static function exitWithStatus($isError, $extra = NULL) {
|
||||||
header("Content-type: text/xml");
|
$output = [];
|
||||||
$xml = new XMLWriter();
|
$output["error"] = $isError;
|
||||||
$xml->openURI("php://output");
|
|
||||||
$xml->startDocument("1.0");
|
|
||||||
$xml->setIndent(true);
|
|
||||||
$xml->startElement("root");
|
|
||||||
$xml->writeElement("error", (int) $isError);
|
|
||||||
if (!empty($extra)) {
|
if (!empty($extra)) {
|
||||||
foreach ($extra as $key => $value) {
|
foreach ($extra as $key => $value) {
|
||||||
$xml->writeElement($key, $value);
|
$output[$key] = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
header("Content-type: application/json");
|
||||||
$xml->endElement();
|
echo json_encode($output);
|
||||||
$xml->endDocument();
|
|
||||||
$xml->flush();
|
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,9 +109,9 @@
|
|||||||
* @return string URL
|
* @return string URL
|
||||||
*/
|
*/
|
||||||
public static function getBaseUrl() {
|
public static function getBaseUrl() {
|
||||||
$proto = (!isset($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] == "" || $_SERVER["HTTPS"] == "off") ? "http://" : "https://";
|
$proto = (!isset($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] === "" || $_SERVER["HTTPS"] === "off") ? "http://" : "https://";
|
||||||
// Check if we are behind an https proxy
|
// Check if we are behind an https proxy
|
||||||
if (isset($_SERVER["HTTP_X_FORWARDED_PROTO"]) && $_SERVER["HTTP_X_FORWARDED_PROTO"] == "https") {
|
if (isset($_SERVER["HTTP_X_FORWARDED_PROTO"]) && $_SERVER["HTTP_X_FORWARDED_PROTO"] === "https") {
|
||||||
$proto = "https://";
|
$proto = "https://";
|
||||||
}
|
}
|
||||||
$host = isset($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"] : "";
|
$host = isset($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"] : "";
|
||||||
@ -168,7 +162,7 @@
|
|||||||
public static function requestFile($name, $default = NULL) {
|
public static function requestFile($name, $default = NULL) {
|
||||||
if (isset($_FILES[$name])) {
|
if (isset($_FILES[$name])) {
|
||||||
$files = $_FILES[$name];
|
$files = $_FILES[$name];
|
||||||
if (isset($files["name"]) && isset($files["type"]) && isset($files["size"]) && isset($files["tmp_name"])) {
|
if (isset($files["name"], $files["type"], $files["size"], $files["tmp_name"])) {
|
||||||
return $_FILES[$name];
|
return $_FILES[$name];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -189,26 +183,23 @@
|
|||||||
private static function requestString($name, $default, $type) {
|
private static function requestString($name, $default, $type) {
|
||||||
if (is_string(($val = self::requestValue($name, $default, $type)))) {
|
if (is_string(($val = self::requestValue($name, $default, $type)))) {
|
||||||
return trim($val);
|
return trim($val);
|
||||||
} else {
|
|
||||||
return $val;
|
|
||||||
}
|
}
|
||||||
|
return $val;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function requestInt($name, $default, $type) {
|
private static function requestInt($name, $default, $type) {
|
||||||
if (is_float(($val = self::requestValue($name, $default, $type, FILTER_VALIDATE_FLOAT)))) {
|
if (is_float(($val = self::requestValue($name, $default, $type, FILTER_VALIDATE_FLOAT)))) {
|
||||||
return (int) round($val);
|
return (int) round($val);
|
||||||
} else {
|
|
||||||
return self::requestValue($name, $default, $type, FILTER_VALIDATE_INT);
|
|
||||||
}
|
}
|
||||||
|
return self::requestValue($name, $default, $type, FILTER_VALIDATE_INT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function requestValue($name, $default, $type, $filters = FILTER_DEFAULT, $flags = NULL) {
|
private static function requestValue($name, $default, $type, $filters = FILTER_DEFAULT, $flags = NULL) {
|
||||||
$input = filter_input($type, $name, $filters, $flags);
|
$input = filter_input($type, $name, $filters, $flags);
|
||||||
if ($input !== false && !is_null($input)) {
|
if ($input !== false && $input !== null) {
|
||||||
return $input;
|
return $input;
|
||||||
} else {
|
|
||||||
return $default;
|
|
||||||
}
|
}
|
||||||
|
return $default;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import uSelect from './select.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class uListItem
|
* @class uListItem
|
||||||
* @property {string} listValue
|
* @property {string} listValue
|
||||||
@ -27,7 +29,12 @@ export default class uListItem {
|
|||||||
* @param {string|number} id
|
* @param {string|number} id
|
||||||
* @param {string|number} value
|
* @param {string|number} value
|
||||||
*/
|
*/
|
||||||
constructor(id, value) {
|
constructor() {
|
||||||
|
this.listValue = uSelect.allValue;
|
||||||
|
this.listText = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
listItem(id, value) {
|
||||||
this.listValue = String(id);
|
this.listValue = String(id);
|
||||||
this.listText = String(value);
|
this.listText = String(value);
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
import { config, lang } from '../initializer.js';
|
import { config, lang } from '../initializer.js';
|
||||||
import MapViewModel from '../mapviewmodel.js';
|
import MapViewModel from '../mapviewmodel.js';
|
||||||
|
import uTrack from '../track.js';
|
||||||
import uUtils from '../utils.js';
|
import uUtils from '../utils.js';
|
||||||
|
|
||||||
// google maps
|
// google maps
|
||||||
@ -52,7 +53,7 @@ export default class GoogleMapsApi {
|
|||||||
* @return {Promise<void, Error>}
|
* @return {Promise<void, Error>}
|
||||||
*/
|
*/
|
||||||
init() {
|
init() {
|
||||||
const params = `?${(config.gkey != null) ? `key=${config.gkey}&` : ''}callback=gm_loaded`;
|
const params = `?${(config.gkey) ? `key=${config.gkey}&` : ''}callback=gm_loaded`;
|
||||||
const gmReady = Promise.all([
|
const gmReady = Promise.all([
|
||||||
GoogleMapsApi.onScriptLoaded(),
|
GoogleMapsApi.onScriptLoaded(),
|
||||||
uUtils.loadScript(`https://maps.googleapis.com/maps/api/js${params}`, 'mapapi_gmaps', GoogleMapsApi.loadTimeoutMs)
|
uUtils.loadScript(`https://maps.googleapis.com/maps/api/js${params}`, 'mapapi_gmaps', GoogleMapsApi.loadTimeoutMs)
|
||||||
@ -125,7 +126,7 @@ export default class GoogleMapsApi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Display track
|
* Display track
|
||||||
* @param {uTrack} track
|
* @param {uPositionSet} track
|
||||||
* @param {boolean} update Should fit bounds if true
|
* @param {boolean} update Should fit bounds if true
|
||||||
*/
|
*/
|
||||||
displayTrack(track, update) {
|
displayTrack(track, update) {
|
||||||
@ -159,7 +160,7 @@ export default class GoogleMapsApi {
|
|||||||
// update polyline
|
// update polyline
|
||||||
const position = track.positions[i];
|
const position = track.positions[i];
|
||||||
const coordinates = new google.maps.LatLng(position.latitude, position.longitude);
|
const coordinates = new google.maps.LatLng(position.latitude, position.longitude);
|
||||||
if (track.continuous) {
|
if (track instanceof uTrack) {
|
||||||
path.push(coordinates);
|
path.push(coordinates);
|
||||||
}
|
}
|
||||||
latlngbounds.extend(coordinates);
|
latlngbounds.extend(coordinates);
|
||||||
@ -175,7 +176,7 @@ export default class GoogleMapsApi {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
google.maps.event.removeListener(zListener)
|
google.maps.event.removeListener(zListener);
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,13 +220,12 @@ export default class GoogleMapsApi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set marker
|
* Set marker
|
||||||
* @param {uTrack} track
|
* @param {uPositionSet} track
|
||||||
* @param {number} id
|
* @param {number} id
|
||||||
*/
|
*/
|
||||||
setMarker(id, track) {
|
setMarker(id, track) {
|
||||||
// marker
|
// marker
|
||||||
const position = track.positions[id];
|
const position = track.positions[id];
|
||||||
const posLen = track.length;
|
|
||||||
// noinspection JSCheckFunctionSignatures
|
// noinspection JSCheckFunctionSignatures
|
||||||
const marker = new google.maps.Marker({
|
const marker = new google.maps.Marker({
|
||||||
position: new google.maps.LatLng(position.latitude, position.longitude),
|
position: new google.maps.LatLng(position.latitude, position.longitude),
|
||||||
@ -234,9 +234,9 @@ export default class GoogleMapsApi {
|
|||||||
});
|
});
|
||||||
const isExtra = position.hasComment() || position.hasImage();
|
const isExtra = position.hasComment() || position.hasImage();
|
||||||
let icon;
|
let icon;
|
||||||
if (id === posLen - 1) {
|
if (track.isLastPosition(id)) {
|
||||||
icon = GoogleMapsApi.getMarkerIcon(config.colorStop, true, isExtra);
|
icon = GoogleMapsApi.getMarkerIcon(config.colorStop, true, isExtra);
|
||||||
} else if (id === 0) {
|
} else if (track.isFirstPosition(id)) {
|
||||||
icon = GoogleMapsApi.getMarkerIcon(config.colorStart, true, isExtra);
|
icon = GoogleMapsApi.getMarkerIcon(config.colorStart, true, isExtra);
|
||||||
} else {
|
} else {
|
||||||
icon = GoogleMapsApi.getMarkerIcon(isExtra ? config.colorExtra : config.colorNormal, false, isExtra);
|
icon = GoogleMapsApi.getMarkerIcon(isExtra ? config.colorExtra : config.colorNormal, false, isExtra);
|
||||||
@ -295,7 +295,6 @@ export default class GoogleMapsApi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get map bounds
|
* Get map bounds
|
||||||
* eg. ((52.20105108685229, 20.789387865580238), (52.292069558807135, 21.172192736185707))
|
|
||||||
* @returns {number[]} Bounds [ lon_sw, lat_sw, lon_ne, lat_ne ]
|
* @returns {number[]} Bounds [ lon_sw, lat_sw, lon_ne, lat_ne ]
|
||||||
*/
|
*/
|
||||||
getBounds() {
|
getBounds() {
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
import MapViewModel from '../mapviewmodel.js';
|
import MapViewModel from '../mapviewmodel.js';
|
||||||
import { config } from '../initializer.js';
|
import { config } from '../initializer.js';
|
||||||
|
import uTrack from '../track.js';
|
||||||
import uUtils from '../utils.js';
|
import uUtils from '../utils.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,7 +90,7 @@ export default class OpenLayersApi {
|
|||||||
*/
|
*/
|
||||||
init() {
|
init() {
|
||||||
uUtils.addCss('css/ol.css', 'ol_css');
|
uUtils.addCss('css/ol.css', 'ol_css');
|
||||||
const olReady = ol ? Promise.resolve() : import(/* webpackChunkName : "ol" */'../lib/ol.js').then((m) => { ol = m });
|
const olReady = ol ? Promise.resolve() : import(/* webpackChunkName : "ol" */'../lib/ol.js').then((m) => { ol = m; });
|
||||||
return olReady.then(() => {
|
return olReady.then(() => {
|
||||||
this.initMap();
|
this.initMap();
|
||||||
this.initLayers();
|
this.initLayers();
|
||||||
@ -412,7 +413,7 @@ export default class OpenLayersApi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Display track
|
* Display track
|
||||||
* @param {uTrack} track Track
|
* @param {uPositionSet} track Track
|
||||||
* @param {boolean} update Should fit bounds if true
|
* @param {boolean} update Should fit bounds if true
|
||||||
*/
|
*/
|
||||||
displayTrack(track, update) {
|
displayTrack(track, update) {
|
||||||
@ -423,7 +424,7 @@ export default class OpenLayersApi {
|
|||||||
for (let i = start; i < track.length; i++) {
|
for (let i = start; i < track.length; i++) {
|
||||||
this.setMarker(i, track);
|
this.setMarker(i, track);
|
||||||
}
|
}
|
||||||
if (track.continuous) {
|
if (track instanceof uTrack) {
|
||||||
let lineString;
|
let lineString;
|
||||||
if (this.layerTrack && this.layerTrack.getSource().getFeatures().length) {
|
if (this.layerTrack && this.layerTrack.getSource().getFeatures().length) {
|
||||||
lineString = this.layerTrack.getSource().getFeatures()[0].getGeometry();
|
lineString = this.layerTrack.getSource().getFeatures()[0].getGeometry();
|
||||||
@ -492,23 +493,23 @@ export default class OpenLayersApi {
|
|||||||
/**
|
/**
|
||||||
* Get marker style
|
* Get marker style
|
||||||
* @param {number} id
|
* @param {number} id
|
||||||
* @param {uTrack} track
|
* @param {uPositionSet} track
|
||||||
* @return {Style}
|
* @return {Style}
|
||||||
*/
|
*/
|
||||||
getMarkerStyle(id, track) {
|
getMarkerStyle(id, track) {
|
||||||
const position = track.positions[id];
|
const position = track.positions[id];
|
||||||
let iconStyle = this.markerStyles.normal;
|
let iconStyle = this.markerStyles.normal;
|
||||||
if (position.hasComment() || position.hasImage()) {
|
if (position.hasComment() || position.hasImage()) {
|
||||||
if (id === track.length - 1) {
|
if (track.isLastPosition(id)) {
|
||||||
iconStyle = this.markerStyles.stopExtra;
|
iconStyle = this.markerStyles.stopExtra;
|
||||||
} else if (id === 0) {
|
} else if (track.isFirstPosition(id)) {
|
||||||
iconStyle = this.markerStyles.startExtra;
|
iconStyle = this.markerStyles.startExtra;
|
||||||
} else {
|
} else {
|
||||||
iconStyle = this.markerStyles.extra;
|
iconStyle = this.markerStyles.extra;
|
||||||
}
|
}
|
||||||
} else if (id === track.length - 1) {
|
} else if (track.isLastPosition(id)) {
|
||||||
iconStyle = this.markerStyles.stop;
|
iconStyle = this.markerStyles.stop;
|
||||||
} else if (id === 0) {
|
} else if (track.isFirstPosition(id)) {
|
||||||
iconStyle = this.markerStyles.start;
|
iconStyle = this.markerStyles.start;
|
||||||
}
|
}
|
||||||
return iconStyle;
|
return iconStyle;
|
||||||
@ -517,7 +518,7 @@ export default class OpenLayersApi {
|
|||||||
/**
|
/**
|
||||||
* Set marker
|
* Set marker
|
||||||
* @param {number} id
|
* @param {number} id
|
||||||
* @param {uTrack} track
|
* @param {uPositionSet} track
|
||||||
*/
|
*/
|
||||||
setMarker(id, track) {
|
setMarker(id, track) {
|
||||||
// marker
|
// marker
|
||||||
|
220
js/src/track.js
Normal file
220
js/src/track.js
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
/*
|
||||||
|
* μlogger
|
||||||
|
*
|
||||||
|
* Copyright(C) 2019 Bartek Fabiszewski (www.fabiszewski.net)
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 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 General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { auth } from './initializer.js';
|
||||||
|
import uAjax from './ajax.js';
|
||||||
|
import uPosition from './position.js';
|
||||||
|
import uPositionSet from './positionset.js';
|
||||||
|
import uUser from './user.js';
|
||||||
|
import uUtils from './utils.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of positions representing user's track
|
||||||
|
* @class uTrack
|
||||||
|
* @property {number} id
|
||||||
|
* @property {string} name
|
||||||
|
* @property {uUser} user
|
||||||
|
* @property {uPosition[]} positions
|
||||||
|
* @property {PlotData} plotData
|
||||||
|
*/
|
||||||
|
export default class uTrack extends uPositionSet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} id
|
||||||
|
* @param {string} name
|
||||||
|
* @param {uUser} user
|
||||||
|
*/
|
||||||
|
constructor(id, name, user) {
|
||||||
|
super();
|
||||||
|
if (!Number.isSafeInteger(id) || id <= 0 || !name || !(user instanceof uUser)) {
|
||||||
|
throw new Error('Invalid argument for track constructor');
|
||||||
|
}
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.user = user;
|
||||||
|
this.plotData = [];
|
||||||
|
this.maxId = 0;
|
||||||
|
this.listItem(id, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
super.clear();
|
||||||
|
this.maxId = 0;
|
||||||
|
this.plotData.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {uTrack} track
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
isEqualTo(track) {
|
||||||
|
return !!track && track.id === this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
get hasPlotData() {
|
||||||
|
return this.plotData.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get track data from json
|
||||||
|
* @param {Object[]} posArr Positions data
|
||||||
|
* @param {boolean=} isUpdate If true append to old data
|
||||||
|
*/
|
||||||
|
fromJson(posArr, isUpdate = false) {
|
||||||
|
let totalMeters = 0;
|
||||||
|
let totalSeconds = 0;
|
||||||
|
let positions = [];
|
||||||
|
if (isUpdate && this.hasPositions) {
|
||||||
|
positions = this.positions;
|
||||||
|
const last = positions[this.length - 1];
|
||||||
|
totalMeters = last.totalMeters;
|
||||||
|
totalSeconds = last.totalSeconds;
|
||||||
|
} else {
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
for (const pos of posArr) {
|
||||||
|
const position = uPosition.fromJson(pos);
|
||||||
|
totalMeters += position.meters;
|
||||||
|
totalSeconds += position.seconds;
|
||||||
|
position.totalMeters = totalMeters;
|
||||||
|
position.totalSeconds = totalSeconds;
|
||||||
|
positions.push(position);
|
||||||
|
if (position.altitude != null) {
|
||||||
|
this.plotData.push({ x: position.totalMeters, y: position.altitude });
|
||||||
|
}
|
||||||
|
if (position.id > this.maxId) {
|
||||||
|
this.maxId = position.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// update at the end to avoid observers update invidual points
|
||||||
|
this.positions = positions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} id
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
isLastPosition(id) {
|
||||||
|
return this.length > 0 && id === this.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} id
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
isFirstPosition(id) {
|
||||||
|
return this.length > 0 && id === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch track positions
|
||||||
|
* @return {Promise<void, Error>}
|
||||||
|
*/
|
||||||
|
fetchPositions() {
|
||||||
|
const params = {
|
||||||
|
userid: this.user.id,
|
||||||
|
trackid: this.id
|
||||||
|
};
|
||||||
|
if (this.maxId) {
|
||||||
|
params.afterid = this.maxId;
|
||||||
|
}
|
||||||
|
return uPositionSet.fetch(params).then((_positions) => {
|
||||||
|
this.fromJson(_positions, params.afterid > 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch track with latest position of a user.
|
||||||
|
* @param {uUser} user
|
||||||
|
* @return {Promise<?uTrack, Error>}
|
||||||
|
*/
|
||||||
|
static fetchLatest(user) {
|
||||||
|
return this.fetch({
|
||||||
|
last: true,
|
||||||
|
userid: user.id
|
||||||
|
}).then((_positions) => {
|
||||||
|
if (_positions.length) {
|
||||||
|
const track = new uTrack(_positions[0].trackid, _positions[0].trackname, user);
|
||||||
|
track.fromJson(_positions);
|
||||||
|
return track;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch tracks for given user
|
||||||
|
* @throws
|
||||||
|
* @param {uUser} user
|
||||||
|
* @return {Promise<uTrack[], Error>}
|
||||||
|
*/
|
||||||
|
static fetchList(user) {
|
||||||
|
return uAjax.get('utils/gettracks.php', { userid: user.id }).then(
|
||||||
|
/**
|
||||||
|
* @param {Array.<{id: number, name: string}>} _tracks
|
||||||
|
* @return {uTrack[]}
|
||||||
|
*/
|
||||||
|
(_tracks) => {
|
||||||
|
const tracks = [];
|
||||||
|
for (const track of _tracks) {
|
||||||
|
tracks.push(new uTrack(track.id, track.name, user));
|
||||||
|
}
|
||||||
|
return tracks;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export to file
|
||||||
|
* @param {string} type File type
|
||||||
|
*/
|
||||||
|
export(type) {
|
||||||
|
if (this.hasPositions) {
|
||||||
|
const url = `utils/export.php?type=${type}&userid=${this.user.id}&trackid=${this.id}`;
|
||||||
|
uUtils.openUrl(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports tracks submited with HTML form and returns last imported track id
|
||||||
|
* @param {HTMLFormElement} form
|
||||||
|
* @return {Promise<uTrack[], Error>}
|
||||||
|
*/
|
||||||
|
static import(form) {
|
||||||
|
if (!auth.isAuthenticated) {
|
||||||
|
throw new Error('User not authenticated');
|
||||||
|
}
|
||||||
|
return uAjax.post('utils/import.php', form)
|
||||||
|
.then(
|
||||||
|
/**
|
||||||
|
* @param {Array.<{id: number, name: string}>} _tracks
|
||||||
|
* @return {uTrack[]}
|
||||||
|
*/
|
||||||
|
(_tracks) => {
|
||||||
|
const tracks = [];
|
||||||
|
for (const track of _tracks) {
|
||||||
|
tracks.push(new uTrack(track.id, track.name, auth.user));
|
||||||
|
}
|
||||||
|
return tracks;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -33,9 +33,13 @@ export default class uUser extends uListItem {
|
|||||||
* @param {string} login
|
* @param {string} login
|
||||||
*/
|
*/
|
||||||
constructor(id, login) {
|
constructor(id, login) {
|
||||||
super(id, login);
|
super();
|
||||||
|
if (!Number.isSafeInteger(id) || id <= 0) {
|
||||||
|
throw new Error('Invalid argument for user constructor');
|
||||||
|
}
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.login = login;
|
this.login = login;
|
||||||
|
this.listItem(id, login);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
317
js/src/utils.js
Normal file
317
js/src/utils.js
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
/*
|
||||||
|
* μlogger
|
||||||
|
*
|
||||||
|
* Copyright(C) 2019 Bartek Fabiszewski (www.fabiszewski.net)
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 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 General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default class uUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set cookie
|
||||||
|
* @param {string} name
|
||||||
|
* @param {(string|number)} value
|
||||||
|
* @param {?number=} days Default validity is 30 days, null = never expire
|
||||||
|
*/
|
||||||
|
static setCookie(name, value, days = 30) {
|
||||||
|
let expires = '';
|
||||||
|
if (days) {
|
||||||
|
const date = new Date();
|
||||||
|
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||||
|
expires = `; expires=${date.toUTCString()}`;
|
||||||
|
}
|
||||||
|
document.cookie = `ulogger_${name}=${value}${expires}; path=/`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sprintf, naive approach, only %s, %d supported
|
||||||
|
* @param {string} fmt String
|
||||||
|
* @param {...(string|number)=} params Optional parameters
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
static sprintf(fmt, params) { // eslint-disable-line no-unused-vars
|
||||||
|
const args = Array.prototype.slice.call(arguments);
|
||||||
|
const format = args.shift();
|
||||||
|
let i = 0;
|
||||||
|
return format.replace(/%%|%s|%d/g, (match) => {
|
||||||
|
if (match === '%%') {
|
||||||
|
return '%';
|
||||||
|
}
|
||||||
|
return (typeof args[i] !== 'undefined') ? args[i++] : match;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add script tag
|
||||||
|
* @param {string} url attribute
|
||||||
|
* @param {string} id attribute
|
||||||
|
* @param {Function=} onload
|
||||||
|
* @param {Function=} onerror
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line max-params
|
||||||
|
static addScript(url, id, onload, onerror) {
|
||||||
|
if (id && document.getElementById(id)) {
|
||||||
|
if (onload instanceof Function) {
|
||||||
|
onload();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const tag = document.createElement('script');
|
||||||
|
tag.type = 'text/javascript';
|
||||||
|
tag.src = url;
|
||||||
|
if (id) {
|
||||||
|
tag.id = id;
|
||||||
|
}
|
||||||
|
tag.async = true;
|
||||||
|
if (onload instanceof Function) {
|
||||||
|
tag.onload = onload;
|
||||||
|
}
|
||||||
|
if (onerror instanceof Function) {
|
||||||
|
tag.onerror = () => onerror(new Error(`error loading ${id} script`));
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementsByTagName('head')[0].appendChild(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load script with timeout
|
||||||
|
* @param {string} url URL
|
||||||
|
* @param {string} id Element id
|
||||||
|
* @param {number=} ms Timeout in ms
|
||||||
|
* @return {Promise<void, Error>}
|
||||||
|
*/
|
||||||
|
static loadScript(url, id, ms = 10000) {
|
||||||
|
const scriptLoaded = new Promise(
|
||||||
|
(resolve, reject) => uUtils.addScript(url, id, resolve, reject));
|
||||||
|
const timeout = this.timeoutPromise(ms);
|
||||||
|
return Promise.race([ scriptLoaded, timeout ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static timeoutPromise(ms) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const tid = setTimeout(() => {
|
||||||
|
clearTimeout(tid);
|
||||||
|
reject(new Error(`timeout (${ms} ms).`));
|
||||||
|
}, ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode string for HTML
|
||||||
|
* @param {string} s
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
static htmlEncode(s) {
|
||||||
|
return s.replace(/&/g, '&')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert hex string and opacity to an rgba string
|
||||||
|
* @param {string} hex
|
||||||
|
* @param {number} opacity
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
static hexToRGBA(hex, opacity) {
|
||||||
|
return 'rgba(' + (hex = hex.replace('#', ''))
|
||||||
|
.match(new RegExp('(.{' + hex.length / 3 + '})', 'g'))
|
||||||
|
.map((l) => parseInt(hex.length % 2 ? l + l : l, 16))
|
||||||
|
.concat(opacity || 1).join(',') + ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add link tag with type css
|
||||||
|
* @param {string} url attribute
|
||||||
|
* @param {string} id attribute
|
||||||
|
*/
|
||||||
|
static addCss(url, id) {
|
||||||
|
if (id && document.getElementById(id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const tag = document.createElement('link');
|
||||||
|
tag.type = 'text/css';
|
||||||
|
tag.rel = 'stylesheet';
|
||||||
|
tag.href = url;
|
||||||
|
if (id) {
|
||||||
|
tag.id = id;
|
||||||
|
}
|
||||||
|
document.getElementsByTagName('head')[0].appendChild(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove HTML element
|
||||||
|
* @param {string} id Element ID
|
||||||
|
*/
|
||||||
|
static removeElementById(id) {
|
||||||
|
const tag = document.getElementById(id);
|
||||||
|
if (tag && tag.parentNode) {
|
||||||
|
tag.parentNode.removeChild(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} html HTML representing a single element
|
||||||
|
* @return {Node}
|
||||||
|
*/
|
||||||
|
static nodeFromHtml(html) {
|
||||||
|
const template = document.createElement('template');
|
||||||
|
template.innerHTML = html;
|
||||||
|
return template.content.firstChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} html HTML representing a single element
|
||||||
|
* @return {NodeList}
|
||||||
|
*/
|
||||||
|
static nodesFromHtml(html) {
|
||||||
|
const template = document.createElement('template');
|
||||||
|
template.innerHTML = html;
|
||||||
|
return template.content.childNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {NodeList} nodeList
|
||||||
|
* @param {string} selector
|
||||||
|
* @return {?Element}
|
||||||
|
*/
|
||||||
|
static querySelectorInList(nodeList, selector) {
|
||||||
|
for (const node of nodeList) {
|
||||||
|
if (node instanceof HTMLElement) {
|
||||||
|
const el = node.querySelector(selector);
|
||||||
|
if (el) {
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws On invalid input
|
||||||
|
* @param {*} input
|
||||||
|
* @param {boolean=} isNullable
|
||||||
|
* @return {(null|number)}
|
||||||
|
*/
|
||||||
|
static getFloat(input, isNullable = false) {
|
||||||
|
return uUtils.getParsed(input, isNullable, 'float');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws On invalid input
|
||||||
|
* @param {*} input
|
||||||
|
* @param {boolean=} isNullable
|
||||||
|
* @return {(null|number)}
|
||||||
|
*/
|
||||||
|
static getInteger(input, isNullable = false) {
|
||||||
|
return uUtils.getParsed(input, isNullable, 'int');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws On invalid input
|
||||||
|
* @param {*} input
|
||||||
|
* @param {boolean=} isNullable
|
||||||
|
* @return {(null|string)}
|
||||||
|
*/
|
||||||
|
static getString(input, isNullable = false) {
|
||||||
|
return uUtils.getParsed(input, isNullable, 'string');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws On invalid input
|
||||||
|
* @param {*} input
|
||||||
|
* @param {boolean} isNullable
|
||||||
|
* @param {string} type
|
||||||
|
* @return {(null|number|string)}
|
||||||
|
*/
|
||||||
|
static getParsed(input, isNullable, type) {
|
||||||
|
if (isNullable && input === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let output;
|
||||||
|
switch (type) {
|
||||||
|
case 'float':
|
||||||
|
output = parseFloat(input);
|
||||||
|
break;
|
||||||
|
case 'int':
|
||||||
|
output = parseInt(input);
|
||||||
|
break;
|
||||||
|
case 'string':
|
||||||
|
output = String(input);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error('Unknown type');
|
||||||
|
}
|
||||||
|
if (typeof input === 'undefined' || input === null ||
|
||||||
|
(type !== 'string' && isNaN(output))) {
|
||||||
|
throw new Error('Invalid value');
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format date to date, time and time zone strings
|
||||||
|
* Simplify zone name, eg.
|
||||||
|
* date: 2017-06-14, time: 11:42:19, zone: GMT+2 CEST
|
||||||
|
* @param {Date} date
|
||||||
|
* @return {{date: string, time: string, zone: string}}
|
||||||
|
*/
|
||||||
|
static getTimeString(date) {
|
||||||
|
let timeZone = '';
|
||||||
|
const dateStr = `${date.getFullYear()}-${(`0${date.getMonth() + 1}`).slice(-2)}-${(`0${date.getDate()}`).slice(-2)}`;
|
||||||
|
const timeStr = date.toTimeString().replace(/^\s*([^ ]+)([^(]*)(\([^)]*\))*/,
|
||||||
|
// eslint-disable-next-line max-params
|
||||||
|
(_, hours, zone, dst) => {
|
||||||
|
if (zone) {
|
||||||
|
timeZone = zone.replace(/(0(?=[1-9]00))|(00\b)/g, '');
|
||||||
|
if (dst && (/[A-Z]/).test(dst)) {
|
||||||
|
timeZone += dst.match(/\b[A-Z]+/g).join('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hours;
|
||||||
|
});
|
||||||
|
return { date: dateStr, time: timeStr, zone: timeZone };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} url
|
||||||
|
*/
|
||||||
|
static openUrl(url) {
|
||||||
|
window.location.assign(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// seconds to (d) H:M:S
|
||||||
|
Number.prototype.toHMS = function () {
|
||||||
|
let s = this;
|
||||||
|
const d = Math.floor(s / 86400);
|
||||||
|
const h = Math.floor((s % 86400) / 3600);
|
||||||
|
const 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;
|
||||||
|
};
|
@ -21,6 +21,7 @@ import * as gmStub from './googlemaps.stub.js';
|
|||||||
import { config, lang } from '../src/initializer.js'
|
import { config, lang } from '../src/initializer.js'
|
||||||
import GoogleMapsApi from '../src/mapapi/api_gmaps.js';
|
import GoogleMapsApi from '../src/mapapi/api_gmaps.js';
|
||||||
import uPosition from '../src/position.js';
|
import uPosition from '../src/position.js';
|
||||||
|
import uPositionSet from '../src/positionset.js';
|
||||||
import uTrack from '../src/track.js';
|
import uTrack from '../src/track.js';
|
||||||
import uUser from '../src/user.js';
|
import uUser from '../src/user.js';
|
||||||
import uUtils from '../src/utils.js';
|
import uUtils from '../src/utils.js';
|
||||||
@ -230,10 +231,9 @@ describe('Google Maps map API tests', () => {
|
|||||||
|
|
||||||
it('should construct non-continuous track markers without polyline', () => {
|
it('should construct non-continuous track markers without polyline', () => {
|
||||||
// given
|
// given
|
||||||
const track = getTrack();
|
const track = getPositionSet();
|
||||||
spyOn(api, 'setMarker');
|
spyOn(api, 'setMarker');
|
||||||
// when
|
// when
|
||||||
track.continuous = false;
|
|
||||||
api.displayTrack(track, false);
|
api.displayTrack(track, false);
|
||||||
// then
|
// then
|
||||||
expect(api.polies.length).toBe(1);
|
expect(api.polies.length).toBe(1);
|
||||||
@ -473,15 +473,32 @@ describe('Google Maps map API tests', () => {
|
|||||||
expect(GoogleMapsApi.loadTimeoutMs).toEqual(jasmine.any(Number));
|
expect(GoogleMapsApi.loadTimeoutMs).toEqual(jasmine.any(Number));
|
||||||
});
|
});
|
||||||
|
|
||||||
function getTrack(length = 2) {
|
function getSet(length = 2, type) {
|
||||||
const track = new uTrack(1, 'test track', new uUser(1, 'testUser'));
|
let track;
|
||||||
|
if (type === uTrack) {
|
||||||
|
track = new uTrack(1, 'test track', new uUser(1, 'testUser'));
|
||||||
|
} else {
|
||||||
|
track = new uPositionSet();
|
||||||
|
}
|
||||||
track.positions = [];
|
track.positions = [];
|
||||||
|
let lat = 21.01;
|
||||||
|
let lon = 52.23;
|
||||||
for (let i = 0; i < length; i++) {
|
for (let i = 0; i < length; i++) {
|
||||||
track.positions.push(getPosition());
|
track.positions.push(getPosition(lat, lon));
|
||||||
|
lat += 0.5;
|
||||||
|
lon += 0.5;
|
||||||
}
|
}
|
||||||
return track;
|
return track;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTrack(length = 2) {
|
||||||
|
return getSet(length, uTrack);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPositionSet(length = 2) {
|
||||||
|
return getSet(length, uPositionSet);
|
||||||
|
}
|
||||||
|
|
||||||
function getPosition(latitude = 52.23, longitude = 21.01) {
|
function getPosition(latitude = 52.23, longitude = 21.01) {
|
||||||
const position = new uPosition();
|
const position = new uPosition();
|
||||||
position.latitude = latitude;
|
position.latitude = latitude;
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
import OpenlayersApi from '../src/mapapi/api_openlayers.js';
|
import OpenlayersApi from '../src/mapapi/api_openlayers.js';
|
||||||
import { config } from '../src/initializer.js'
|
import { config } from '../src/initializer.js'
|
||||||
import uPosition from '../src/position.js';
|
import uPosition from '../src/position.js';
|
||||||
|
import uPositionSet from '../src/positionset.js';
|
||||||
import uTrack from '../src/track.js';
|
import uTrack from '../src/track.js';
|
||||||
import uUser from '../src/user.js';
|
import uUser from '../src/user.js';
|
||||||
import uUtils from '../src/utils.js';
|
import uUtils from '../src/utils.js';
|
||||||
@ -276,8 +277,7 @@ describe('Openlayers map API tests', () => {
|
|||||||
api.map.addControl(new ol.control.ZoomToExtent());
|
api.map.addControl(new ol.control.ZoomToExtent());
|
||||||
api.layerTrack = new ol.layer.VectorLayer({ source: new ol.source.Vector() });
|
api.layerTrack = new ol.layer.VectorLayer({ source: new ol.source.Vector() });
|
||||||
api.layerMarkers = new ol.layer.VectorLayer({ source: new ol.source.Vector() });
|
api.layerMarkers = new ol.layer.VectorLayer({ source: new ol.source.Vector() });
|
||||||
const track = getTrack();
|
const track = getPositionSet();
|
||||||
track.continuous = false;
|
|
||||||
spyOn(api, 'setMarker');
|
spyOn(api, 'setMarker');
|
||||||
spyOn(api, 'fitToExtent');
|
spyOn(api, 'fitToExtent');
|
||||||
// when
|
// when
|
||||||
@ -549,8 +549,13 @@ describe('Openlayers map API tests', () => {
|
|||||||
expect(mockViewModel.model.markerSelect).toBe(null);
|
expect(mockViewModel.model.markerSelect).toBe(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
function getTrack(length = 2) {
|
function getSet(length = 2, type) {
|
||||||
const track = new uTrack(1, 'test track', new uUser(1, 'testUser'));
|
let track;
|
||||||
|
if (type === uTrack) {
|
||||||
|
track = new uTrack(1, 'test track', new uUser(1, 'testUser'));
|
||||||
|
} else {
|
||||||
|
track = new uPositionSet();
|
||||||
|
}
|
||||||
track.positions = [];
|
track.positions = [];
|
||||||
let lat = 21.01;
|
let lat = 21.01;
|
||||||
let lon = 52.23;
|
let lon = 52.23;
|
||||||
@ -562,6 +567,14 @@ describe('Openlayers map API tests', () => {
|
|||||||
return track;
|
return track;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTrack(length = 2) {
|
||||||
|
return getSet(length, uTrack);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPositionSet(length = 2) {
|
||||||
|
return getSet(length, uPositionSet);
|
||||||
|
}
|
||||||
|
|
||||||
function getPosition(latitude = 52.23, longitude = 21.01) {
|
function getPosition(latitude = 52.23, longitude = 21.01) {
|
||||||
const position = new uPosition();
|
const position = new uPosition();
|
||||||
position.latitude = latitude;
|
position.latitude = latitude;
|
||||||
|
424
js/test/track.test.js
Normal file
424
js/test/track.test.js
Normal file
@ -0,0 +1,424 @@
|
|||||||
|
/*
|
||||||
|
* μlogger
|
||||||
|
*
|
||||||
|
* Copyright(C) 2019 Bartek Fabiszewski (www.fabiszewski.net)
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 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 General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { auth } from '../src/initializer.js';
|
||||||
|
import uPosition from '../src/position.js';
|
||||||
|
import uTrack from '../src/track.js';
|
||||||
|
import uUser from '../src/user.js';
|
||||||
|
import uUtils from '../src/utils.js';
|
||||||
|
|
||||||
|
|
||||||
|
describe('Track tests', () => {
|
||||||
|
|
||||||
|
let track;
|
||||||
|
|
||||||
|
let posId;
|
||||||
|
let latitude;
|
||||||
|
let longitude;
|
||||||
|
let altitude;
|
||||||
|
let speed;
|
||||||
|
let bearing;
|
||||||
|
let timestamp;
|
||||||
|
let accuracy;
|
||||||
|
let provider;
|
||||||
|
let comment;
|
||||||
|
let image;
|
||||||
|
let username;
|
||||||
|
let trackid;
|
||||||
|
let trackname;
|
||||||
|
let meters;
|
||||||
|
let seconds;
|
||||||
|
|
||||||
|
let jsonPosition;
|
||||||
|
beforeEach(() => {
|
||||||
|
const id = 1;
|
||||||
|
const name = 'test';
|
||||||
|
const user = new uUser(1, 'user');
|
||||||
|
track = new uTrack(id, name, user);
|
||||||
|
|
||||||
|
posId = 110286;
|
||||||
|
latitude = 11.221871666666999;
|
||||||
|
longitude = 22.018848333333001;
|
||||||
|
altitude = -39;
|
||||||
|
speed = 0;
|
||||||
|
bearing = null;
|
||||||
|
timestamp = 1564250017;
|
||||||
|
accuracy = 9;
|
||||||
|
provider = 'gps';
|
||||||
|
comment = null;
|
||||||
|
image = '134_5d3c8fa92ebac.jpg';
|
||||||
|
username = 'test';
|
||||||
|
trackid = 134;
|
||||||
|
trackname = 'Test name';
|
||||||
|
meters = 0;
|
||||||
|
seconds = 0;
|
||||||
|
|
||||||
|
jsonPosition = {
|
||||||
|
'id': posId,
|
||||||
|
'latitude': latitude,
|
||||||
|
'longitude': longitude,
|
||||||
|
'altitude': altitude,
|
||||||
|
'speed': speed,
|
||||||
|
'bearing': bearing,
|
||||||
|
'timestamp': timestamp,
|
||||||
|
'accuracy': accuracy,
|
||||||
|
'provider': provider,
|
||||||
|
'comment': comment,
|
||||||
|
'image': image,
|
||||||
|
'username': username,
|
||||||
|
'trackid': trackid,
|
||||||
|
'trackname': trackname,
|
||||||
|
'meters': meters,
|
||||||
|
'seconds': seconds
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('simple tests', () => {
|
||||||
|
|
||||||
|
it('should throw error when creating uTrack instance without user parameter', () => {
|
||||||
|
// given
|
||||||
|
const id = 1;
|
||||||
|
const name = 'test';
|
||||||
|
// when
|
||||||
|
// then
|
||||||
|
expect(() => new uTrack(id, name)).toThrow(new Error('Invalid argument for track constructor'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create uTrack instance with user parameter', () => {
|
||||||
|
// given
|
||||||
|
const id = 1;
|
||||||
|
const name = 'test';
|
||||||
|
const user = new uUser(1, 'user');
|
||||||
|
// when
|
||||||
|
track = new uTrack(id, name, user);
|
||||||
|
// then
|
||||||
|
expect(track.id).toBe(id);
|
||||||
|
expect(track.name).toBe(name);
|
||||||
|
expect(track.user).toBe(user);
|
||||||
|
expect(track.positions).toEqual([]);
|
||||||
|
expect(track.plotData).toEqual([]);
|
||||||
|
expect(track.maxId).toBe(0);
|
||||||
|
expect(track.listValue).toBe(id.toString());
|
||||||
|
expect(track.listText).toBe(name);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should clear positions data', () => {
|
||||||
|
// given
|
||||||
|
track.positions.push(new uPosition());
|
||||||
|
track.plotData.push({ x: 1, y: 2 });
|
||||||
|
track.maxId = 1;
|
||||||
|
// when
|
||||||
|
track.clear();
|
||||||
|
// then
|
||||||
|
expect(track.positions).toEqual([]);
|
||||||
|
expect(track.plotData).toEqual([]);
|
||||||
|
expect(track.maxId).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return positions length', () => {
|
||||||
|
// given
|
||||||
|
track.positions.push(new uPosition());
|
||||||
|
// when
|
||||||
|
const length = track.length;
|
||||||
|
// then
|
||||||
|
expect(length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true when has positions', () => {
|
||||||
|
// given
|
||||||
|
track.positions.push(new uPosition());
|
||||||
|
// when
|
||||||
|
const result = track.hasPositions;
|
||||||
|
// then
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false when does not have positions', () => {
|
||||||
|
// given
|
||||||
|
track.positions.length = 0;
|
||||||
|
// when
|
||||||
|
const result = track.hasPositions;
|
||||||
|
// then
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true when has plot data', () => {
|
||||||
|
// given
|
||||||
|
track.plotData.push({ x: 1, y: 2 });
|
||||||
|
// when
|
||||||
|
const result = track.hasPlotData;
|
||||||
|
// then
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false when does not have plot data', () => {
|
||||||
|
// given
|
||||||
|
track.plotData.length = 0;
|
||||||
|
// when
|
||||||
|
const result = track.hasPlotData;
|
||||||
|
// then
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be equal to other track with same id', () => {
|
||||||
|
// given
|
||||||
|
track.id = 1;
|
||||||
|
const otherTrack = new uTrack(1, 'other', new uUser(2, 'user2'));
|
||||||
|
// when
|
||||||
|
const result = track.isEqualTo(otherTrack);
|
||||||
|
// then
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not be equal to other track with other id', () => {
|
||||||
|
// given
|
||||||
|
track.id = 1;
|
||||||
|
const otherTrack = new uTrack(2, 'other', new uUser(2, 'user2'));
|
||||||
|
// when
|
||||||
|
const result = track.isEqualTo(otherTrack);
|
||||||
|
// then
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not be equal to null track', () => {
|
||||||
|
// given
|
||||||
|
track.id = 1;
|
||||||
|
const otherTrack = null;
|
||||||
|
// when
|
||||||
|
const result = track.isEqualTo(otherTrack);
|
||||||
|
// then
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse json object to track positions', () => {
|
||||||
|
// when
|
||||||
|
track.fromJson([ jsonPosition ]);
|
||||||
|
// then
|
||||||
|
expect(track.length).toBe(1);
|
||||||
|
expect(track.plotData.length).toBe(1);
|
||||||
|
expect(track.maxId).toBe(posId);
|
||||||
|
const position = track.positions[0];
|
||||||
|
|
||||||
|
expect(position.id).toBe(posId);
|
||||||
|
expect(position.latitude).toBe(latitude);
|
||||||
|
expect(position.longitude).toBe(longitude);
|
||||||
|
expect(position.speed).toBe(speed);
|
||||||
|
expect(position.bearing).toBe(bearing);
|
||||||
|
expect(position.timestamp).toBe(timestamp);
|
||||||
|
expect(position.accuracy).toBe(accuracy);
|
||||||
|
expect(position.provider).toBe(provider);
|
||||||
|
expect(position.comment).toBe(comment);
|
||||||
|
expect(position.image).toBe(image);
|
||||||
|
expect(position.username).toBe(username);
|
||||||
|
expect(position.trackid).toBe(trackid);
|
||||||
|
expect(position.trackname).toBe(trackname);
|
||||||
|
expect(position.meters).toBe(meters);
|
||||||
|
expect(position.seconds).toBe(seconds);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should replace track positions with new ones', () => {
|
||||||
|
const position1 = { ...jsonPosition };
|
||||||
|
position1.id = 100;
|
||||||
|
track.fromJson([ position1 ]);
|
||||||
|
// when
|
||||||
|
track.fromJson([ jsonPosition ]);
|
||||||
|
// then
|
||||||
|
expect(track.length).toBe(1);
|
||||||
|
expect(track.plotData.length).toBe(1);
|
||||||
|
expect(track.maxId).toBe(posId);
|
||||||
|
const position2 = track.positions[0];
|
||||||
|
|
||||||
|
expect(position2.id).toBe(posId);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should append track positions with new ones', () => {
|
||||||
|
const position1 = { ...jsonPosition };
|
||||||
|
position1.id = 100;
|
||||||
|
track.fromJson([ position1 ]);
|
||||||
|
// when
|
||||||
|
track.fromJson([ jsonPosition ], true);
|
||||||
|
// then
|
||||||
|
expect(track.length).toBe(2);
|
||||||
|
expect(track.plotData.length).toBe(2);
|
||||||
|
expect(track.maxId).toBe(Math.max(jsonPosition.id, position1.id));
|
||||||
|
expect(track.positions[0].id).toBe(position1.id);
|
||||||
|
expect(track.positions[1].id).toBe(jsonPosition.id);
|
||||||
|
expect(track.positions[0].totalMeters).toBe(position1.meters);
|
||||||
|
expect(track.positions[1].totalMeters).toBe(position1.meters + jsonPosition.meters);
|
||||||
|
expect(track.positions[0].totalSeconds).toBe(position1.seconds);
|
||||||
|
expect(track.positions[1].totalSeconds).toBe(position1.seconds + jsonPosition.seconds);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ajax tests', () => {
|
||||||
|
const validListResponse = [ { 'id': 145, 'name': 'Track 1' }, { 'id': 144, 'name': 'Track 2' } ];
|
||||||
|
const invalidListResponse = [ { 'name': 'Track 1' }, { 'id': 144, 'name': 'Track 2' } ];
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(XMLHttpRequest.prototype, 'open').and.callThrough();
|
||||||
|
spyOn(XMLHttpRequest.prototype, 'setRequestHeader').and.callThrough();
|
||||||
|
spyOn(XMLHttpRequest.prototype, 'send');
|
||||||
|
spyOnProperty(XMLHttpRequest.prototype, 'readyState').and.returnValue(XMLHttpRequest.DONE);
|
||||||
|
spyOnProperty(XMLHttpRequest.prototype, 'status').and.returnValue(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make successful request and return track array', (done) => {
|
||||||
|
// given
|
||||||
|
const user = new uUser(1, 'testLogin');
|
||||||
|
spyOnProperty(XMLHttpRequest.prototype, 'responseText').and.returnValue(JSON.stringify(validListResponse));
|
||||||
|
// when
|
||||||
|
uTrack.fetchList(user)
|
||||||
|
.then((result) => {
|
||||||
|
expect(XMLHttpRequest.prototype.open).toHaveBeenCalledWith('GET', 'utils/gettracks.php?userid=1', true);
|
||||||
|
expect(result).toEqual(jasmine.arrayContaining([ new uTrack(validListResponse[0].id, validListResponse[0].name, user) ]));
|
||||||
|
expect(result.length).toBe(2);
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
.catch((e) => done.fail(`reject callback called (${e})`));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw error on invalid JSON', (done) => {
|
||||||
|
// given
|
||||||
|
const user = new uUser(1, 'testLogin');
|
||||||
|
spyOnProperty(XMLHttpRequest.prototype, 'responseText').and.returnValue(JSON.stringify(invalidListResponse));
|
||||||
|
// when
|
||||||
|
uTrack.fetchList(user)
|
||||||
|
.then(() => {
|
||||||
|
done.fail('resolve callback called');
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
expect(e).toEqual(jasmine.any(Error));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make successful request and return latest track position for given user', (done) => {
|
||||||
|
// given
|
||||||
|
const user = new uUser(1, 'testLogin');
|
||||||
|
spyOnProperty(XMLHttpRequest.prototype, 'responseText').and.returnValue(JSON.stringify([ jsonPosition ]));
|
||||||
|
// when
|
||||||
|
uTrack.fetchLatest(user)
|
||||||
|
.then((result) => {
|
||||||
|
expect(XMLHttpRequest.prototype.open).toHaveBeenCalledWith('GET', 'utils/getpositions.php?last=true&userid=1', true);
|
||||||
|
expect(result).toBeInstanceOf(uTrack);
|
||||||
|
expect(result.id).toEqual(jsonPosition.trackid);
|
||||||
|
expect(result.length).toBe(1);
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
.catch((e) => done.fail(`reject callback called (${e})`));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make successful request and return null when there are no positions for the user', (done) => {
|
||||||
|
// given
|
||||||
|
const user = new uUser(1, 'testLogin');
|
||||||
|
spyOnProperty(XMLHttpRequest.prototype, 'responseText').and.returnValue(JSON.stringify([]));
|
||||||
|
// when
|
||||||
|
uTrack.fetchLatest(user)
|
||||||
|
.then((result) => {
|
||||||
|
expect(result).toBe(null);
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
.catch((e) => done.fail(`reject callback called (${e})`));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make successful request and fetch track positions', (done) => {
|
||||||
|
// given
|
||||||
|
spyOnProperty(XMLHttpRequest.prototype, 'responseText').and.returnValue(JSON.stringify([ jsonPosition ]));
|
||||||
|
track.clear();
|
||||||
|
// when
|
||||||
|
track.fetchPositions()
|
||||||
|
.then(() => {
|
||||||
|
expect(XMLHttpRequest.prototype.open).toHaveBeenCalledWith('GET', `utils/getpositions.php?userid=${track.user.id}&trackid=${track.id}`, true);
|
||||||
|
expect(track.length).toBe(1);
|
||||||
|
expect(track.positions[0].id).toEqual(jsonPosition.id);
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
.catch((e) => done.fail(`reject callback called (${e})`));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make successful request and append track positions to existing data', (done) => {
|
||||||
|
// given
|
||||||
|
spyOnProperty(XMLHttpRequest.prototype, 'responseText').and.returnValue(JSON.stringify([ jsonPosition ]));
|
||||||
|
track.clear();
|
||||||
|
// when
|
||||||
|
track.fetchPositions()
|
||||||
|
.then(() => {
|
||||||
|
expect(XMLHttpRequest.prototype.open).toHaveBeenCalledWith('GET', `utils/getpositions.php?userid=${track.user.id}&trackid=${track.id}`, true);
|
||||||
|
expect(track.length).toBe(1);
|
||||||
|
expect(track.positions[0].id).toEqual(jsonPosition.id);
|
||||||
|
// eslint-disable-next-line jasmine/no-promise-without-done-fail
|
||||||
|
track.fetchPositions().then(() => {
|
||||||
|
expect(XMLHttpRequest.prototype.open).toHaveBeenCalledWith('GET', `utils/getpositions.php?userid=${track.user.id}&trackid=${track.id}&afterid=${track.positions[0].id}`, true);
|
||||||
|
expect(track.length).toBe(2);
|
||||||
|
expect(track.positions[0].id).toEqual(jsonPosition.id);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((e) => done.fail(`reject callback called (${e})`));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should make successful track import request', (done) => {
|
||||||
|
// given
|
||||||
|
const authUser = new uUser(1, 'admin');
|
||||||
|
spyOnProperty(auth, 'isAuthenticated').and.returnValue(true);
|
||||||
|
spyOnProperty(auth, 'user').and.returnValue(authUser);
|
||||||
|
spyOnProperty(XMLHttpRequest.prototype, 'responseText').and.returnValue(JSON.stringify(validListResponse));
|
||||||
|
const form = document.createElement('form');
|
||||||
|
// when
|
||||||
|
uTrack.import(form)
|
||||||
|
.then((tracks) => {
|
||||||
|
expect(XMLHttpRequest.prototype.open).toHaveBeenCalledWith('POST', 'utils/import.php', true);
|
||||||
|
expect(XMLHttpRequest.prototype.send).toHaveBeenCalledWith(new FormData(form));
|
||||||
|
expect(tracks.length).toBe(2);
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
.catch((e) => done.fail(`reject callback called (${e})`));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail on import request without authorized user', () => {
|
||||||
|
// given
|
||||||
|
const form = document.createElement('form');
|
||||||
|
// when
|
||||||
|
expect(() => uTrack.import(form)).toThrowError(/auth/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not open export url when track has no positions', () => {
|
||||||
|
// given
|
||||||
|
spyOn(uUtils, 'openUrl');
|
||||||
|
const type = 'ext';
|
||||||
|
// when
|
||||||
|
track.export(type);
|
||||||
|
// then
|
||||||
|
expect(uUtils.openUrl).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should open export url', () => {
|
||||||
|
// given
|
||||||
|
track.positions.push(new uPosition());
|
||||||
|
spyOn(uUtils, 'openUrl');
|
||||||
|
const type = 'ext';
|
||||||
|
// when
|
||||||
|
track.export(type);
|
||||||
|
// then
|
||||||
|
expect(uUtils.openUrl).toHaveBeenCalledWith(`utils/export.php?type=${type}&userid=${track.user.id}&trackid=${track.id}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -26,7 +26,7 @@ $auth = new uAuth();
|
|||||||
$userId = uUtils::getInt('userid');
|
$userId = uUtils::getInt('userid');
|
||||||
$trackId = uUtils::getInt('trackid');
|
$trackId = uUtils::getInt('trackid');
|
||||||
$afterId = uUtils::getInt('afterid');
|
$afterId = uUtils::getInt('afterid');
|
||||||
$last = uUtils::getInt('last');
|
$last = uUtils::getBool('last');
|
||||||
|
|
||||||
$positionsArr = [];
|
$positionsArr = [];
|
||||||
if ($userId) {
|
if ($userId) {
|
||||||
@ -54,7 +54,7 @@ if ($positionsArr === false) {
|
|||||||
$result = [ "error" => true ];
|
$result = [ "error" => true ];
|
||||||
} else if (!empty($positionsArr)) {
|
} else if (!empty($positionsArr)) {
|
||||||
foreach ($positionsArr as $position) {
|
foreach ($positionsArr as $position) {
|
||||||
$distance = !$last && isset($prevPosition) ? $position->distanceTo($prevPosition) : 0;
|
$meters = !$last && isset($prevPosition) ? $position->distanceTo($prevPosition) : 0;
|
||||||
$seconds = !$last && isset($prevPosition) ? $position->secondsTo($prevPosition) : 0;
|
$seconds = !$last && isset($prevPosition) ? $position->secondsTo($prevPosition) : 0;
|
||||||
$result[] = [
|
$result[] = [
|
||||||
"id" => $position->id,
|
"id" => $position->id,
|
||||||
@ -71,7 +71,7 @@ if ($positionsArr === false) {
|
|||||||
"username" => $position->userLogin,
|
"username" => $position->userLogin,
|
||||||
"trackid" => $position->trackId,
|
"trackid" => $position->trackId,
|
||||||
"trackname" => $position->trackName,
|
"trackname" => $position->trackName,
|
||||||
"distance" => round($distance),
|
"meters" => round($meters),
|
||||||
"seconds" => $seconds
|
"seconds" => $seconds
|
||||||
];
|
];
|
||||||
$prevPosition = $position;
|
$prevPosition = $position;
|
||||||
|
@ -32,24 +32,14 @@ if ($userId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
header("Content-type: text/xml");
|
$result = [];
|
||||||
$xml = new XMLWriter();
|
if ($tracksArr === false) {
|
||||||
$xml->openURI("php://output");
|
$result = [ "error" => true ];
|
||||||
$xml->startDocument("1.0");
|
} else if (!empty($tracksArr)) {
|
||||||
$xml->setIndent(true);
|
foreach ($tracksArr as $track) {
|
||||||
$xml->startElement('root');
|
$result[] = [ "id" => $track->id, "name" => $track->name ];
|
||||||
|
|
||||||
if (!empty($tracksArr)) {
|
|
||||||
foreach ($tracksArr as $aTrack) {
|
|
||||||
$xml->startElement("track");
|
|
||||||
$xml->writeElement("trackid", $aTrack->id);
|
|
||||||
$xml->writeElement("trackname", $aTrack->name);
|
|
||||||
$xml->endElement();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
header("Content-type: application/json");
|
||||||
$xml->endElement();
|
echo json_encode($result);
|
||||||
$xml->endDocument();
|
|
||||||
$xml->flush();
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
@ -71,14 +71,14 @@ if ($gpx === false) {
|
|||||||
}
|
}
|
||||||
uUtils::exitWithError($message);
|
uUtils::exitWithError($message);
|
||||||
}
|
}
|
||||||
else if ($gpx->getName() != "gpx") {
|
else if ($gpx->getName() !== "gpx") {
|
||||||
uUtils::exitWithError($lang["iparsefailure"]);
|
uUtils::exitWithError($lang["iparsefailure"]);
|
||||||
}
|
}
|
||||||
else if (empty($gpx->trk)) {
|
else if (empty($gpx->trk)) {
|
||||||
uUtils::exitWithError($lang["idatafailure"]);
|
uUtils::exitWithError($lang["idatafailure"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$trackCnt = 0;
|
$trackList = [];
|
||||||
foreach ($gpx->trk as $trk) {
|
foreach ($gpx->trk as $trk) {
|
||||||
$trackName = empty($trk->name) ? $gpxName : (string) $trk->name;
|
$trackName = empty($trk->name) ? $gpxName : (string) $trk->name;
|
||||||
$metaName = empty($gpx->metadata->name) ? NULL : (string) $gpx->metadata->name;
|
$metaName = empty($gpx->metadata->name) ? NULL : (string) $gpx->metadata->name;
|
||||||
@ -92,7 +92,7 @@ foreach ($gpx->trk as $trk) {
|
|||||||
|
|
||||||
foreach($trk->trkseg as $segment) {
|
foreach($trk->trkseg as $segment) {
|
||||||
foreach($segment->trkpt as $point) {
|
foreach($segment->trkpt as $point) {
|
||||||
if (!isset($point["lat"]) || !isset($point["lon"])) {
|
if (!isset($point["lat"], $point["lon"])) {
|
||||||
$track->delete();
|
$track->delete();
|
||||||
uUtils::exitWithError($lang["iparsefailure"]);
|
uUtils::exitWithError($lang["iparsefailure"]);
|
||||||
}
|
}
|
||||||
@ -105,7 +105,7 @@ foreach ($gpx->trk as $trk) {
|
|||||||
$provider = "gps";
|
$provider = "gps";
|
||||||
if (!empty($point->extensions)) {
|
if (!empty($point->extensions)) {
|
||||||
// parse ulogger extensions
|
// parse ulogger extensions
|
||||||
$ext = $point->extensions->children('ulogger', TRUE);
|
$ext = $point->extensions->children('ulogger', true);
|
||||||
if (count($ext->speed)) { $speed = (double) $ext->speed; }
|
if (count($ext->speed)) { $speed = (double) $ext->speed; }
|
||||||
if (count($ext->bearing)) { $bearing = (double) $ext->bearing; }
|
if (count($ext->bearing)) { $bearing = (double) $ext->bearing; }
|
||||||
if (count($ext->accuracy)) { $accuracy = (int) $ext->accuracy; }
|
if (count($ext->accuracy)) { $accuracy = (int) $ext->accuracy; }
|
||||||
@ -122,13 +122,12 @@ foreach ($gpx->trk as $trk) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($posCnt) {
|
if ($posCnt) {
|
||||||
$trackCnt++;
|
array_unshift($trackList, [ "id" => $track->id, "name" => $track->name ]);
|
||||||
} else {
|
} else {
|
||||||
$track->delete();
|
$track->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return last track id and tracks count
|
header("Content-type: application/json");
|
||||||
uUtils::exitWithSuccess([ "trackid" => $trackId, "trackcnt" => $trackCnt ]);
|
echo json_encode($trackList);
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user