2024-06-16 12:12:20 +00:00
|
|
|
|
var watchID = null;
|
|
|
|
|
var map = null;
|
|
|
|
|
var firstStep = true;
|
|
|
|
|
var marker = null;
|
|
|
|
|
var followUser = false;
|
|
|
|
|
var drawTrack = false;
|
|
|
|
|
var currentPlatform = null;
|
|
|
|
|
var polyline = null;
|
|
|
|
|
var bgGeo = null;
|
2024-06-16 14:36:58 +00:00
|
|
|
|
var mapInit = 'map';
|
2024-06-16 12:12:20 +00:00
|
|
|
|
|
|
|
|
|
var prevTimestamp = null;
|
|
|
|
|
var prevCoords = [0,0];
|
|
|
|
|
var MAX_DISTANCE = 50; // Максимальное допустимое расстояние (в метрах) между двумя измерениями
|
|
|
|
|
var MIN_TIME_DIFF = 2000; // Минимальный допустимый промежуток времени (в миллисекундах) между двумя измерениями
|
|
|
|
|
|
|
|
|
|
var i_Latitude = null;
|
|
|
|
|
var i_Longitude = null;
|
|
|
|
|
var i_Altitude = null;
|
|
|
|
|
var i_Accuracy = null;
|
|
|
|
|
var i_AltitudeAccuracy = null;
|
|
|
|
|
var i_Heading = null;
|
|
|
|
|
var i_Speed = null;
|
|
|
|
|
|
|
|
|
|
var maxAttempts = 3;
|
|
|
|
|
var attempts = 0;
|
|
|
|
|
|
|
|
|
|
var track = [];
|
|
|
|
|
|
|
|
|
|
page('/', loadMainPage);
|
|
|
|
|
|
|
|
|
|
page('/nalychevo', loadNalychevoPage);
|
|
|
|
|
|
|
|
|
|
page('/m-n-one', loadNalychevoOnePage);
|
|
|
|
|
page('/map-nal-one',loadMapNalychevoOnePage);
|
|
|
|
|
|
|
|
|
|
page('/m-n-two', loadNalychevoTwoPage);
|
2024-06-16 14:36:58 +00:00
|
|
|
|
page('/map-nal-two',loadMapNalychevoTwoPage);
|
|
|
|
|
|
2024-06-16 12:12:20 +00:00
|
|
|
|
page('/m-n-three', loadNalychevoThreePage);
|
2024-06-16 14:36:58 +00:00
|
|
|
|
page('/map-nal-three',loadMapNalychevoThreePage);
|
|
|
|
|
|
|
|
|
|
page('/bistrinskiy', loadBistinskyPage);
|
2024-06-16 12:12:20 +00:00
|
|
|
|
|
2024-06-16 14:36:58 +00:00
|
|
|
|
page('/m-b-one', loadBistrinskiyOnePage);
|
|
|
|
|
page('/map-bir-one', loadMapBistrinskiyOnePage);
|
|
|
|
|
|
|
|
|
|
page('/m-b-two', loadBistrinskiyTwoPage);
|
|
|
|
|
page('/map-bir-two', loadMapBistrinskiyTwoPage);
|
|
|
|
|
|
|
|
|
|
page('/m-b-three', loadBistrinskiyThreePage);
|
|
|
|
|
page('/map-bir-three', loadMapBistrinskiyThreePage);
|
|
|
|
|
|
|
|
|
|
page('/south-cam', loadSouthCamPage);
|
|
|
|
|
|
|
|
|
|
page('/m-sc-one', loadSouthCamOnePage);
|
|
|
|
|
page('/map-sc-one', loadMapSouthCamOnePage);
|
2024-06-16 12:12:20 +00:00
|
|
|
|
|
|
|
|
|
page('/info', loadInfoPage);
|
|
|
|
|
page('/profile', loadProfilePage);
|
|
|
|
|
page('/reg',loadRegPage);
|
|
|
|
|
page('/map', loadMapPage);
|
|
|
|
|
page('/camera', openCamera);
|
|
|
|
|
page();
|
|
|
|
|
|
|
|
|
|
document.addEventListener("deviceready", onDeviceReady, false);
|
|
|
|
|
|
|
|
|
|
function onDeviceReady(){
|
|
|
|
|
currentPlatform = device.platform;
|
|
|
|
|
|
|
|
|
|
if(currentPlatform !== 'browser'){
|
|
|
|
|
// Получаем текущую ориентацию экрана
|
|
|
|
|
var currentOrientation = screen.orientation.type;
|
|
|
|
|
|
|
|
|
|
// Если текущая ориентация не вертикальная, то меняем ее на вертикальную
|
|
|
|
|
if (currentOrientation !== 'portrait-primary' && currentOrientation !== 'portrait-secondary') {
|
|
|
|
|
screen.orientation.angle = 90; // Устанавливаем угол в 90 градусов (вертикальная ориентация)
|
|
|
|
|
screen.orientation.lock('portrait'); // Фиксируем вертикальную ориентацию
|
|
|
|
|
} else {
|
|
|
|
|
screen.orientation.lock('portrait'); // Фиксируем вертикальную ориентацию, если она уже вертикальная
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log('platform is ' + currentPlatform);
|
|
|
|
|
var permissions = cordova.plugins.permissions;
|
|
|
|
|
console.log('Устройство готово!');
|
|
|
|
|
$('#content').empty();
|
|
|
|
|
$('#content').append(
|
|
|
|
|
'<div class="container">' +
|
|
|
|
|
' <div class="row">' +
|
|
|
|
|
' <div class="col d-flex h-100 w-100">' +
|
|
|
|
|
' <div id="data" class="m-auto">' +
|
|
|
|
|
' <p>Устройство готово!</p>' +
|
|
|
|
|
' </div>' +
|
|
|
|
|
' </div>' +
|
|
|
|
|
' </div>' +
|
|
|
|
|
'</div>'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
function checkPermission() {
|
|
|
|
|
$('#data').append(
|
|
|
|
|
'<p>Проверка разрешения ... </p>'
|
|
|
|
|
);
|
|
|
|
|
permissions.hasPermission(permissions.ACCESS_FINE_LOCATION, function(status){
|
|
|
|
|
if(!status.hasPermission) {
|
|
|
|
|
requestPermission();
|
|
|
|
|
} else {
|
|
|
|
|
$('#data').append(
|
|
|
|
|
'<p>Разрешение есть можно работать!</p>'
|
|
|
|
|
);
|
|
|
|
|
if(currentPlatform !== 'browser'){
|
|
|
|
|
configureBackgroundGeolocation();
|
|
|
|
|
}
|
|
|
|
|
loadMainPage();
|
|
|
|
|
}
|
|
|
|
|
}, function(){
|
|
|
|
|
$('#data').append(
|
|
|
|
|
'<p>Ошибка при проверке получения разрешения!</p>'
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function requestPermission() {
|
|
|
|
|
$('#data').append(
|
|
|
|
|
'<p>Разрешения нет пробуем получить ...</p>'
|
|
|
|
|
);
|
|
|
|
|
permissions.requestPermission(permissions.ACCESS_FINE_LOCATION, function(status){
|
|
|
|
|
if(status.hasPermission) {
|
|
|
|
|
$('#data').append(
|
|
|
|
|
'<p>Разрешение получено!</p>'
|
|
|
|
|
);
|
|
|
|
|
if(currentPlatform !== 'browser'){
|
|
|
|
|
configureBackgroundGeolocation();
|
|
|
|
|
}
|
|
|
|
|
loadMainPage();
|
|
|
|
|
} else {
|
|
|
|
|
$('#data').append(
|
|
|
|
|
'<p>Разрешение отклонено!</p>'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}, function(){
|
|
|
|
|
$('#data').append(
|
|
|
|
|
'<p>Ошибка получения разрешения!</p>'
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
checkPermission();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function configureBackgroundGeolocation() {
|
|
|
|
|
bgGeo = window.BackgroundGeolocation;
|
|
|
|
|
|
|
|
|
|
var config = {
|
|
|
|
|
desiredAccuracy: 0,
|
|
|
|
|
stationaryRadius: 20,
|
|
|
|
|
distanceFilter: 30,
|
|
|
|
|
notificationTitle: 'Background tracking',
|
|
|
|
|
notificationText: 'ENABLED',
|
|
|
|
|
debug: false,
|
|
|
|
|
interval: 5000,
|
|
|
|
|
fastestInterval: 5000,
|
|
|
|
|
activitiesInterval: 10000,
|
|
|
|
|
stopOnTerminate: false,
|
|
|
|
|
startForeground: true,
|
|
|
|
|
notificationIconColor: '#FEDD1E',
|
|
|
|
|
notificationIconLarge: 'mappointer_large',
|
|
|
|
|
notificationIconSmall: 'mappointer_small'
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Инициализация плагина
|
|
|
|
|
bgGeo.configure(config, function(location) {
|
|
|
|
|
// Обработка полученной геолокации в фоновом режиме
|
|
|
|
|
console.log('[BackgroundGeolocation] location: ', location);
|
|
|
|
|
|
|
|
|
|
// Добавление координат в track
|
|
|
|
|
track.push({ lat: location.latitude, lng: location.longitude });
|
|
|
|
|
|
|
|
|
|
// Другая ваша логика обработки координат
|
|
|
|
|
}, function (error){console.error('Ошибка при настройке плагина: ' + error);});
|
|
|
|
|
|
|
|
|
|
// Запуск службы геолокации в фоновом режиме
|
|
|
|
|
bgGeo.start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function enableInsomnia() {
|
|
|
|
|
if (window.plugins && window.plugins.insomnia) {
|
|
|
|
|
window.plugins.insomnia.keepAwake();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function disableInsomnia() {
|
|
|
|
|
if (window.plugins && window.plugins.insomnia) {
|
|
|
|
|
window.plugins.insomnia.allowSleepAgain();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadMainPage(ctx, next) {
|
|
|
|
|
fetch('main.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
stopTracker(watchID);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadNalychevoPage(ctx, next){
|
|
|
|
|
fetch('nalychevo.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
stopTracker(watchID);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadNalychevoOnePage(ctx, next){
|
|
|
|
|
fetch('m-n-one.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
stopTracker(watchID);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadNalychevoTwoPage(ctx, next){
|
|
|
|
|
fetch('m-n-two.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
stopTracker(watchID);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadNalychevoThreePage(ctx, next){
|
|
|
|
|
fetch('m-n-three.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
stopTracker(watchID);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-16 14:36:58 +00:00
|
|
|
|
function loadBistinskyPage(ctx, next){
|
|
|
|
|
fetch('bistrinskiy.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
stopTracker(watchID);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadBistrinskiyOnePage(ctx, next){
|
|
|
|
|
fetch('m-b-one.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
stopTracker(watchID);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadMapBistrinskiyOnePage(ctx, next){
|
|
|
|
|
fetch('reg-on-road.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
mapInit = 'map-bistrinskiy-one';
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadBistrinskiyTwoPage(ctx, next){
|
|
|
|
|
fetch('m-b-two.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
stopTracker(watchID);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadMapBistrinskiyTwoPage(ctx, next){
|
|
|
|
|
fetch('reg-on-road.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
mapInit = 'map-bistrinskiy-two';
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadBistrinskiyThreePage(ctx, next){
|
|
|
|
|
fetch('m-b-three.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
stopTracker(watchID);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadMapBistrinskiyThreePage(ctx, next){
|
|
|
|
|
fetch('reg-on-road.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
mapInit = 'map-bistrinskiy-three';
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadSouthCamPage(ctx, next){
|
|
|
|
|
fetch('south-cam.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
stopTracker(watchID);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadSouthCamOnePage(ctx, next){
|
|
|
|
|
fetch('m-sc-one.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
stopTracker(watchID);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadMapSouthCamOnePage(ctx, next){
|
|
|
|
|
fetch('reg-on-road.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
mapInit = 'map-south-cam-one';
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-16 12:12:20 +00:00
|
|
|
|
|
|
|
|
|
function loadInfoPage(ctx, next) {
|
|
|
|
|
fetch('info.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
stopTracker(watchID);
|
|
|
|
|
hammerTime();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadRegPage(ctx, next) {
|
|
|
|
|
fetch('reg.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
stopTracker(watchID);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadProfilePage(ctx, next) {
|
|
|
|
|
var jwt = loadJWT();
|
|
|
|
|
if(jwt){
|
|
|
|
|
fetch('profile.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
var userData = loadUserData();
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
$('#dataUsername').empty();
|
|
|
|
|
$('#dataUsername').append(
|
|
|
|
|
'Профиль \"' + userData.username + '\"'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$('#dataMail').empty();
|
|
|
|
|
$('#dataMail').append(
|
|
|
|
|
'<span>' + userData.email + '</span>'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$('#dataRole').empty();
|
|
|
|
|
$('#dataRole').append(
|
|
|
|
|
'<span>' + userData.roles[0] + '</span>'
|
|
|
|
|
);
|
|
|
|
|
stopTracker(watchID);
|
|
|
|
|
});
|
|
|
|
|
}else{
|
|
|
|
|
fetch('welcome.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
stopTracker(watchID);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadMapPage(ctx, next) {
|
|
|
|
|
fetch('map.html')
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
document.getElementById('content').innerHTML = html;
|
|
|
|
|
calcMapHeight();
|
|
|
|
|
showCamera();
|
|
|
|
|
createMap();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadMapNalychevoOnePage(ctx, next) {
|
2024-06-16 14:36:58 +00:00
|
|
|
|
fetch('reg-on-road.html')
|
2024-06-16 12:12:20 +00:00
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
mapInit = 'map-nalychevo-one';
|
2024-06-16 14:36:58 +00:00
|
|
|
|
document.getElementById('content').innerHTML = html;
|
2024-06-16 12:12:20 +00:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-16 14:36:58 +00:00
|
|
|
|
function loadMapNalychevoTwoPage(ctx, next) {
|
|
|
|
|
fetch('reg-on-road.html')
|
2024-06-16 12:12:20 +00:00
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
mapInit = 'map-nalychevo-two';
|
2024-06-16 14:36:58 +00:00
|
|
|
|
document.getElementById('content').innerHTML = html;
|
2024-06-16 12:12:20 +00:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadMapNalychevoThreePage(ctx, next){
|
2024-06-16 14:36:58 +00:00
|
|
|
|
fetch('reg-on-road.html')
|
2024-06-16 12:12:20 +00:00
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(html => {
|
|
|
|
|
mapInit = 'map-nalychevo-three';
|
2024-06-16 14:36:58 +00:00
|
|
|
|
document.getElementById('content').innerHTML = html;
|
2024-06-16 12:12:20 +00:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function openCamera(ctx,next){
|
|
|
|
|
navigator.camera.getPicture(cameraOnSuccess, onError, {
|
|
|
|
|
quality: 50,
|
|
|
|
|
destinationType: Camera.DestinationType.FILE_URI,
|
|
|
|
|
saveToPhotoAlbum: false, // Сохранить фото в альбом
|
|
|
|
|
correctOrientation: false // Исправить ориентацию изображения
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var imageContent;
|
|
|
|
|
var modal = document.getElementById('photoModal');
|
|
|
|
|
var img = document.getElementById('photoPreview');
|
|
|
|
|
|
|
|
|
|
function cameraOnSuccess(imageURI) {
|
|
|
|
|
imageContent = imageURI;
|
|
|
|
|
|
|
|
|
|
if (currentPlatform === 'browser') {
|
|
|
|
|
imageContent = 'data:image/png;base64,' + imageURI;
|
|
|
|
|
img.src = imageContent;
|
|
|
|
|
} else {
|
|
|
|
|
window.resolveLocalFileSystemURL(imageURI, function(fileEntry) {
|
|
|
|
|
fileEntry.file(function(file) {
|
|
|
|
|
var blob = file.slice(0, file.size, file.type); // создаем объект Blob из объекта File с помощью метода slice
|
|
|
|
|
var reader = new FileReader();
|
|
|
|
|
reader.onloadend = function(event) {
|
|
|
|
|
imageContent = event.target.result;
|
|
|
|
|
img.src = imageContent;
|
|
|
|
|
};
|
|
|
|
|
reader.readAsDataURL(blob);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
modal.style.display = 'block';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
document.getElementById('savePhoto').addEventListener('click', function() {
|
|
|
|
|
var comment = document.getElementById('photoComment').value;
|
|
|
|
|
savePhotoData(imageContent, comment);
|
|
|
|
|
modal.style.display = 'none';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
document.getElementById('cancelPhoto').addEventListener('click', function() {
|
|
|
|
|
modal.style.display = 'none';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
document.getElementById('closeModal').addEventListener('click', function() {
|
|
|
|
|
modal.style.display = 'none';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
function savePhotoData(imageURI, comment) {
|
|
|
|
|
var latitude = prevCoords[0];
|
|
|
|
|
var longitude = prevCoords[1];
|
|
|
|
|
|
|
|
|
|
var photoData = {
|
|
|
|
|
uuid: generateUUID(),
|
|
|
|
|
eventdate: prevTimestamp,
|
|
|
|
|
image: imageURI,
|
|
|
|
|
comment: comment,
|
|
|
|
|
latitude: latitude,
|
|
|
|
|
longitude: longitude
|
|
|
|
|
};
|
|
|
|
|
saveData(photoData);
|
|
|
|
|
addPhotoMarker(photoData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function saveData(data){
|
|
|
|
|
var db = window.sqlitePlugin.openDatabase({ name: 'trail.db', location: 'default' });
|
|
|
|
|
db.transaction(function (tx) {
|
|
|
|
|
tx.executeSql(
|
|
|
|
|
'CREATE TABLE IF NOT EXISTS photos (id INTEGER PRIMARY KEY AUTOINCREMENT, uuid TEXT, eventdate TEXT, image TEXT, comment TEXT, latitude TEXT, longitude TEXT)'
|
|
|
|
|
);
|
|
|
|
|
tx.executeSql('INSERT INTO photos (uuid, eventdate, image, comment, latitude, longitude) VALUES (?, ?, ?, ?, ?, ?)', [
|
|
|
|
|
data.uuid,
|
|
|
|
|
data.timestamp,
|
|
|
|
|
data.image,
|
|
|
|
|
data.comment,
|
|
|
|
|
data.latitude,
|
|
|
|
|
data.longitude
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadData(callback) {
|
|
|
|
|
var db = window.sqlitePlugin.openDatabase({ name: 'trail.db', location: 'default' });
|
|
|
|
|
|
|
|
|
|
db.transaction(function (tx) {
|
|
|
|
|
tx.executeSql(
|
|
|
|
|
'CREATE TABLE IF NOT EXISTS photos (id INTEGER PRIMARY KEY AUTOINCREMENT, uuid TEXT, eventdate TEXT, image TEXT, comment TEXT, latitude TEXT, longitude TEXT)'
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var data = [];
|
|
|
|
|
|
|
|
|
|
db.transaction(function (tx) {
|
|
|
|
|
tx.executeSql('SELECT * FROM photos', [], function (tx, results) {
|
|
|
|
|
var len = results.rows.length;
|
|
|
|
|
for (let i = 0; i < len; i++) {
|
|
|
|
|
let row = results.rows.item(i);
|
|
|
|
|
data.push(row);
|
|
|
|
|
}
|
|
|
|
|
console.log('Data loaded:', data);
|
|
|
|
|
callback(data);
|
|
|
|
|
});
|
|
|
|
|
}, function (error) {
|
|
|
|
|
console.error('Error loading data:', error);
|
|
|
|
|
callback(data); // Возвращаем пустой массив в случае ошибки
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function sendPhotoToServer(id) {
|
|
|
|
|
var parts = id.split('_');
|
|
|
|
|
var originalId = parts[parts.length - 1];
|
|
|
|
|
console.log(id,originalId);
|
|
|
|
|
var psb = document.getElementById(id);
|
|
|
|
|
var userData = JSON.parse(psb.getAttribute('user-data').replace(/"/g, '"'));
|
|
|
|
|
var photoData = JSON.parse(psb.getAttribute('photo-data').replace(/"/g, '"'));
|
|
|
|
|
|
|
|
|
|
console.log(userData, photoData);
|
|
|
|
|
|
|
|
|
|
var formData = new FormData();
|
|
|
|
|
formData.append('id', photoData.uuid);
|
|
|
|
|
formData.append('eventdate', photoData.eventdate);
|
|
|
|
|
formData.append('message', photoData.comment);
|
|
|
|
|
formData.append('latitude', photoData.latitude);
|
|
|
|
|
formData.append('longitude', photoData.longitude);
|
|
|
|
|
formData.append('file', dataURItoBlob(photoData.image));
|
|
|
|
|
|
|
|
|
|
console.log(formData);
|
|
|
|
|
|
|
|
|
|
fetch('https://api.beartrack.ru/v1/upload', {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: {
|
|
|
|
|
'x-access-token': userData.accessToken
|
|
|
|
|
},
|
|
|
|
|
body: formData
|
|
|
|
|
})
|
|
|
|
|
.then(response => {
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
throw new Error('Network response was not ok ' + response.statusText);
|
|
|
|
|
}
|
|
|
|
|
return response.json();
|
|
|
|
|
})
|
|
|
|
|
.then(data => {
|
|
|
|
|
//var sendError = document.getElementById('send-error-' + originalId);
|
|
|
|
|
var sendError = $('#send-error-' + originalId);
|
|
|
|
|
sendError.removeClass('text-danger');
|
|
|
|
|
sendError.addClass('text-success');
|
|
|
|
|
sendError.append(
|
|
|
|
|
'Успешно загружено!'
|
|
|
|
|
);
|
|
|
|
|
console.log('Photo sent successfully', data);
|
|
|
|
|
})
|
|
|
|
|
.catch(error => {
|
|
|
|
|
var sendError = document.getElementById('send-error-' + originalId);
|
|
|
|
|
console.log(sendError);
|
|
|
|
|
sendError.innerText = error;
|
|
|
|
|
console.error('There was a problem with the fetch operation:', error);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function dataURItoBlob(dataURI) {
|
|
|
|
|
var byteString = atob(dataURI.split(',')[1]);
|
|
|
|
|
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
|
|
|
|
|
var ab = new ArrayBuffer(byteString.length);
|
|
|
|
|
var ia = new Uint8Array(ab);
|
|
|
|
|
for (var i = 0; i < byteString.length; i++) {
|
|
|
|
|
ia[i] = byteString.charCodeAt(i);
|
|
|
|
|
}
|
|
|
|
|
return new Blob([ab], {type: mimeString});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function addPhotoMarker(photoData) {
|
|
|
|
|
var MyIconContentLayout = ymaps.templateLayoutFactory.createClass(
|
|
|
|
|
'<div class="rounded-circle border border-dark border-2 d-flex align-items-center justify-content-center" style="width: 50px; height: 50px; overflow: hidden;">' +
|
|
|
|
|
' <img src="' + photoData.image + '" class="img-fluid" alt="" style="width: 100%; height: 100%; object-fit: cover;" />' +
|
|
|
|
|
'</div>'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
var userData = loadUserData();
|
|
|
|
|
var myBalloonContent = '';
|
|
|
|
|
if(userData){
|
|
|
|
|
myBalloonContent = '' +
|
|
|
|
|
'<div class="card" style="width: 18rem; overflow: hidden">\n' +
|
|
|
|
|
' <div class="photo-container" style="position: relative; width: 100%; padding-bottom: 100%; overflow: hidden;">\n' +
|
|
|
|
|
' <img id="photoPreview" class="card-img-top" src="' + photoData.image + '" alt="Photo" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover;">\n' +
|
|
|
|
|
' </div>' +
|
|
|
|
|
' <div class="card-body">\n' +
|
|
|
|
|
' <p class="card-text fs-4 text-center pt-1">' + photoData.comment + '</p>\n' +
|
|
|
|
|
' <p id="send-error-' + photoData.uuid + '" class="text-center fs-5 text-danger" style="height: 50px"></p>' +
|
|
|
|
|
' <button type="button" id="photoSendButton_' + photoData.uuid + '" user-data="' + JSON.stringify(userData).replace(/"/g, '"') + '" photo-data="' + JSON.stringify(photoData).replace(/"/g, '"') + '" class="btn btn-success" onclick="sendPhotoToServer(this.id)" style="width: 100%">Отправить</button>\n' +
|
|
|
|
|
' </div>\n' +
|
|
|
|
|
'</div>';
|
|
|
|
|
}else{
|
|
|
|
|
myBalloonContent = '' +
|
|
|
|
|
'<div class="card" style="width: 18rem; overflow: hidden">\n' +
|
|
|
|
|
' <div class="photo-container" style="position: relative; width: 100%; padding-bottom: 100%; overflow: hidden;">\n' +
|
|
|
|
|
' <img id="photoPreview" class="card-img-top" src="' + photoData.image + '" alt="Photo" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover;">\n' +
|
|
|
|
|
' </div>' +
|
|
|
|
|
' <div class="card-body">\n' +
|
|
|
|
|
' <p class="card-text fs-4 text-center">' + photoData.comment + '</p>\n' +
|
|
|
|
|
' </div>\n' +
|
|
|
|
|
'</div>';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var placemark = new ymaps.Placemark(
|
|
|
|
|
[photoData.latitude, photoData.longitude],
|
|
|
|
|
{
|
|
|
|
|
balloonContent: myBalloonContent,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
iconLayout: 'default#imageWithContent',
|
|
|
|
|
iconImageHref: '', // путь к изображению, если нужно
|
|
|
|
|
iconImageSize: [50, 50], // размер иконки
|
|
|
|
|
iconContentLayout: MyIconContentLayout,
|
|
|
|
|
iconImageOffset: [-25, -25], // смещение, чтобы центрировать иконку
|
|
|
|
|
balloonPanelMaxMapArea: 0 // убираем ограничение размера балуна
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
map.geoObjects.add(placemark);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function calcMapHeight(){
|
|
|
|
|
// Вычисляем высоту header
|
|
|
|
|
var headerHeight = document.querySelector('header').offsetHeight;
|
|
|
|
|
|
|
|
|
|
// Вычисляем высоту footer
|
|
|
|
|
var footerHeight = document.querySelector('footer').offsetHeight;
|
|
|
|
|
|
|
|
|
|
// Устанавливаем высоту для карты, учитывая высоту header и footer
|
|
|
|
|
var mapHeight = window.innerHeight - (headerHeight + footerHeight);
|
|
|
|
|
document.getElementById('map').style.height = mapHeight + 'px';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createMap(){
|
|
|
|
|
ymaps.ready(init);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function init(){
|
|
|
|
|
console.log('настройка карты: ', mapInit);
|
|
|
|
|
console.log('создаю собственный слой карты');
|
|
|
|
|
|
|
|
|
|
var MyLayer = function () {
|
|
|
|
|
var subdomains = ['a', 'b', 'c'];
|
|
|
|
|
|
|
|
|
|
var getTileUrl = function (tile, zoom) {
|
|
|
|
|
var s = subdomains[Math.floor(Math.random() * subdomains.length)];
|
|
|
|
|
return `https://${s}.tile.opentopomap.org/${zoom}/${tile[0]}/${tile[1]}.png`;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var layer = new ymaps.Layer(getTileUrl, {projection: ymaps.projection.sphericalMercator});
|
|
|
|
|
|
|
|
|
|
layer.getCopyrights = function () {
|
|
|
|
|
return ymaps.vow.resolve('');
|
|
|
|
|
};
|
|
|
|
|
layer.getZoomRange = function () {
|
|
|
|
|
return ymaps.vow.resolve([0, 17]);
|
|
|
|
|
};
|
|
|
|
|
return layer;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ymaps.layer.storage.add('my#layer', MyLayer);
|
|
|
|
|
var myMapType = new ymaps.MapType('Топологическая', ['my#layer']);
|
|
|
|
|
ymaps.mapType.storage.add('yandex#myLayer', myMapType);
|
|
|
|
|
|
|
|
|
|
var MyLayer2 = function () {
|
|
|
|
|
var subdomains = ['a', 'b', 'c'];
|
|
|
|
|
|
|
|
|
|
var getTileUrl = function (tile, zoom) {
|
|
|
|
|
var s = subdomains[Math.floor(Math.random() * subdomains.length)];
|
|
|
|
|
return `https://${s}.tile.openstreetmap.org/${zoom}/${tile[0]}/${tile[1]}.png`;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var layer = new ymaps.Layer(getTileUrl, {projection: ymaps.projection.sphericalMercator});
|
|
|
|
|
|
|
|
|
|
layer.getCopyrights = function () {
|
|
|
|
|
return ymaps.vow.resolve('');
|
|
|
|
|
};
|
|
|
|
|
layer.getZoomRange = function () {
|
|
|
|
|
return ymaps.vow.resolve([0, 17]);
|
|
|
|
|
};
|
|
|
|
|
return layer;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ymaps.layer.storage.add('street#layer', MyLayer2);
|
|
|
|
|
var myMapType2 = new ymaps.MapType('Openstreetmap', ['street#layer']);
|
|
|
|
|
ymaps.mapType.storage.add('yandex#streetLayer', myMapType2);
|
|
|
|
|
|
|
|
|
|
console.log('создаю карту');
|
|
|
|
|
map = new ymaps.Map('map', {
|
|
|
|
|
center: [58.0000, 160.0000],
|
|
|
|
|
zoom: 5,
|
|
|
|
|
type: 'yandex#myLayer',
|
|
|
|
|
controls: ['typeSelector']
|
|
|
|
|
}, {
|
|
|
|
|
suppressMapOpenBlock: true // Убираем надпись "открыть в Яндекс.Картах"
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var typeSelector = map.controls.get('typeSelector');
|
|
|
|
|
typeSelector.addMapType('yandex#myLayer', 'Топологическая');
|
|
|
|
|
typeSelector.addMapType('yandex#streetLayer', 'openstreetmap');
|
|
|
|
|
|
|
|
|
|
console.log('создаю маркер');
|
|
|
|
|
var MyIconContentLayout = ymaps.templateLayoutFactory.createClass(
|
|
|
|
|
'<div class="rotating-icon" style="transform:rotate({{options.rotate}}deg);">' +
|
|
|
|
|
' {% include "default#image" %}',
|
|
|
|
|
'</div>'
|
|
|
|
|
);
|
|
|
|
|
marker = new ymaps.Placemark([58.0000, 160.0000], {},
|
|
|
|
|
{
|
|
|
|
|
iconLayout: MyIconContentLayout,
|
|
|
|
|
iconImageHref: 'img/marker-cursor.svg',
|
|
|
|
|
iconImageSize: [42, 42],
|
|
|
|
|
iconImageOffset: [-21, -21],
|
|
|
|
|
iconRotate: 0
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
console.log('создаю кнопки');
|
|
|
|
|
var followButton = new ymaps.control.Button({
|
|
|
|
|
data: {
|
|
|
|
|
content: '<i class="bi bi-person fs-4"></i>'
|
|
|
|
|
},
|
|
|
|
|
options: {
|
|
|
|
|
selectOnClick: true
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
var trackerButton = new ymaps.control.Button({
|
|
|
|
|
data: {
|
|
|
|
|
content: '<i class="bi bi-person-walking fs-4"></i>'
|
|
|
|
|
},
|
|
|
|
|
options: {
|
|
|
|
|
selectOnClick: true
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
i_Latitude = new ymaps.control.Button({
|
|
|
|
|
data: {
|
|
|
|
|
content: '<p>' + 0 + '</p>'
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
i_Longitude = new ymaps.control.Button({
|
|
|
|
|
data: {
|
|
|
|
|
content: '<p>' + 0 + '</p>'
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
i_Altitude = new ymaps.control.Button({
|
|
|
|
|
data: {
|
|
|
|
|
content: '<p>' + 0 + '</p>'
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
i_Accuracy = new ymaps.control.Button({
|
|
|
|
|
data: {
|
|
|
|
|
content: '<p>' + 0 + '</p>'
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
i_AltitudeAccuracy = new ymaps.control.Button({
|
|
|
|
|
data: {
|
|
|
|
|
content: '<p>' + 0 + '</p>'
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
i_Heading = new ymaps.control.Button({
|
|
|
|
|
data: {
|
|
|
|
|
content: '<p>' + 0 + '</p>'
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
i_Speed = new ymaps.control.Button({
|
|
|
|
|
data: {
|
|
|
|
|
content: '<p>' + 0 + '</p>'
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
i_Latitude.options.set('maxWidth', 300);
|
|
|
|
|
i_Longitude.options.set('maxWidth', 300);
|
|
|
|
|
i_Altitude.options.set('maxWidth', 300);
|
|
|
|
|
i_Accuracy.options.set('maxWidth', 300);
|
|
|
|
|
i_AltitudeAccuracy.options.set('maxWidth', 300);
|
|
|
|
|
i_Heading.options.set('maxWidth', 300);
|
|
|
|
|
i_Speed.options.set('maxWidth', 300);
|
|
|
|
|
|
|
|
|
|
// Создаем контейнер для кнопок
|
|
|
|
|
var buttonsContainer = new ymaps.control.ListBox({
|
|
|
|
|
data: {
|
|
|
|
|
content:'Данные'
|
|
|
|
|
},
|
|
|
|
|
items: [
|
|
|
|
|
i_Latitude,
|
|
|
|
|
i_Longitude,
|
|
|
|
|
i_Altitude,
|
|
|
|
|
i_Accuracy,
|
|
|
|
|
i_AltitudeAccuracy,
|
|
|
|
|
i_Heading,
|
|
|
|
|
i_Speed
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
|
2024-06-16 14:36:58 +00:00
|
|
|
|
//map.controls.add(buttonsContainer, { float: 'right' });
|
2024-06-16 12:12:20 +00:00
|
|
|
|
//map.controls.add(trackerButton, { float: 'left' });
|
|
|
|
|
map.controls.add(followButton);
|
|
|
|
|
|
|
|
|
|
// Обработчик нажатия на кнопку
|
|
|
|
|
followButton.events.add('click', function () {
|
|
|
|
|
followUser = !followUser; // Меняем флаг на противоположный
|
|
|
|
|
if (followUser) {
|
|
|
|
|
followButton.data.set('content', '<i class="bi bi-person-fill fs-4"></i>');
|
|
|
|
|
map.controls.remove(followButton);
|
|
|
|
|
map.controls.add(trackerButton, { float: 'left' });
|
|
|
|
|
map.controls.add(followButton);
|
|
|
|
|
map.geoObjects.add(marker);
|
|
|
|
|
startTracker();
|
|
|
|
|
} else {
|
|
|
|
|
followButton.data.set('content', '<i class="bi bi-person fs-4"></i>');
|
|
|
|
|
map.geoObjects.remove(marker);
|
|
|
|
|
map.controls.remove(trackerButton);
|
|
|
|
|
stopTrackerLight(watchID);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
trackerButton.events.add('click', function () {
|
|
|
|
|
drawTrack = !drawTrack; // Меняем флаг на противоположный
|
|
|
|
|
if (drawTrack) {
|
|
|
|
|
trackerButton.data.set('content', '<i class="bi bi-person-standing fs-4"></i>');
|
|
|
|
|
} else {
|
|
|
|
|
trackerButton.data.set('content', '<i class="bi bi-person-walking fs-4"></i>');
|
|
|
|
|
// Очистите трек, если вы хотите начать новый трек
|
|
|
|
|
track = [];
|
|
|
|
|
// Если на карте есть линия, удалите ее
|
|
|
|
|
if (polyline) {
|
|
|
|
|
map.geoObjects.remove(polyline);
|
|
|
|
|
polyline = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
console.log('пробую добавить трек маршрут');
|
|
|
|
|
if(mapInit === 'map-nalychevo-one'){
|
|
|
|
|
gpxParser(map,'налычево_центральный');
|
|
|
|
|
borderGpxParser(map,'налычево');
|
|
|
|
|
}else if(mapInit === 'map-nalychevo-two'){
|
|
|
|
|
gpxParser(map,'пятая_стройка_налычево');
|
|
|
|
|
borderGpxParser(map,'налычево');
|
|
|
|
|
}else if(mapInit === 'map-nalychevo-three'){
|
|
|
|
|
gpxCombainParser(map,'налычево_таловские',true,'таловские-дзендзур',false)
|
|
|
|
|
borderGpxParser(map,'налычево');
|
2024-06-16 14:36:58 +00:00
|
|
|
|
}else if(mapInit === 'map-bistrinskiy-one'){
|
|
|
|
|
gpxParser(map,'bistrinskiy/1. БП_ Пионерская сопка');
|
|
|
|
|
borderGpxParser(map,'boundry-bistrinsky');
|
|
|
|
|
}else if(mapInit === 'map-bistrinskiy-two'){
|
|
|
|
|
gpxParser(map,'bistrinskiy/2. БП_Белые скалы');
|
|
|
|
|
borderGpxParser(map,'boundry-bistrinsky');
|
|
|
|
|
}else if(mapInit === 'map-bistrinskiy-three'){
|
|
|
|
|
gpxParserReverseControl(map,'bistrinskiy/4. БП_Черемшанка',true);
|
|
|
|
|
borderGpxParser(map,'boundry-bistrinsky');
|
|
|
|
|
}else if(mapInit === 'map-south-cam-one'){
|
|
|
|
|
gpxParserReverseControl(map,'southcam/Восхождение на Горелый',false);
|
|
|
|
|
borderGpxParser(map,'south-camchatskiy');
|
2024-06-16 12:12:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
loadSavedPhotos();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*function startTracker() {
|
|
|
|
|
enableInsomnia();
|
|
|
|
|
watchID = navigator.geolocation.watchPosition(onSuccess,onError,
|
|
|
|
|
{
|
|
|
|
|
enableHighAccuracy: true, // Запрашиваем максимально возможную точность
|
|
|
|
|
//timeout: 5000, // Задаем таймаут в 5 секунд
|
|
|
|
|
maximumAge: 0 // Запрашиваем всегда только свежие данные
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
//startMockGeolocation();
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
function startTracker() {
|
|
|
|
|
console.log('Старт геолокации!');
|
|
|
|
|
enableInsomnia();
|
|
|
|
|
|
|
|
|
|
if(currentPlatform === 'browser'){
|
|
|
|
|
watchID = navigator.geolocation.watchPosition(onSuccess,onError,
|
|
|
|
|
{
|
|
|
|
|
enableHighAccuracy: true, // Запрашиваем максимально возможную точность
|
|
|
|
|
//timeout: 5000, // Задаем таймаут в 5 секунд
|
|
|
|
|
maximumAge: 0 // Запрашиваем всегда только свежие данные
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}else{
|
|
|
|
|
if(bgGeo === null){
|
|
|
|
|
configureBackgroundGeolocation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var options = {
|
|
|
|
|
enableHighAccuracy: true,
|
|
|
|
|
desiredAccuracy: 0,
|
|
|
|
|
stationaryRadius: 20,
|
|
|
|
|
distanceFilter: 30,
|
|
|
|
|
stopOnTerminate: false, // Позволяет работать в фоне
|
|
|
|
|
startForeground: true,
|
|
|
|
|
interval: 5000,
|
|
|
|
|
fastestInterval: 5000,
|
|
|
|
|
activitiesInterval: 10000,
|
|
|
|
|
notificationTitle: 'Background tracking',
|
|
|
|
|
notificationText: 'ENABLED',
|
|
|
|
|
debug: true
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bgGeo.watchPosition(function(location) {
|
|
|
|
|
geolocationLt(location)
|
|
|
|
|
}, function(error) {
|
|
|
|
|
console.error('[BackgroundGeolocation] Error: ', error);
|
|
|
|
|
}, options);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function stopTrackerLight(id){
|
|
|
|
|
if(currentPlatform === 'browser'){
|
|
|
|
|
navigator.geolocation.clearWatch(id);
|
|
|
|
|
}else{
|
|
|
|
|
console.log('останавливаю трекер');
|
|
|
|
|
bgGeo.stop(function() {
|
|
|
|
|
console.log('Трекер успешно остановлен');
|
|
|
|
|
}, function(error) {
|
|
|
|
|
console.error('Ошибка при остановке трекера: ' + error);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
firstStep = true;
|
|
|
|
|
followUser = false;
|
|
|
|
|
drawTrack = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function stopTracker(id){
|
|
|
|
|
stopTrackerLight(id);
|
|
|
|
|
disableInsomnia();
|
|
|
|
|
hideCamera();
|
2024-06-16 14:36:58 +00:00
|
|
|
|
mapInit = 'map';
|
2024-06-16 12:12:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function onSuccess(position){
|
|
|
|
|
console.log('onSuccess','обновление позиции',position);
|
|
|
|
|
// Получаем координаты пользователя и некоторые другие полезные данные
|
|
|
|
|
var latitude = position.coords.latitude;
|
|
|
|
|
var longitude = position.coords.longitude;
|
|
|
|
|
var altitude = position.coords.altitude;
|
|
|
|
|
var accuracy = position.coords.accuracy;
|
|
|
|
|
var altitudeAccuracy = position.coords.altitudeAccuracy;
|
|
|
|
|
var heading = position.coords.heading;
|
|
|
|
|
var speed = position.coords.speed;
|
|
|
|
|
var timestamp = getDate(position.timestamp);
|
|
|
|
|
var zoom = getZoom(speed);
|
|
|
|
|
|
|
|
|
|
if (!prevCoords) {
|
|
|
|
|
prevCoords = [latitude, longitude];
|
|
|
|
|
prevTimestamp = timestamp;
|
|
|
|
|
return;
|
|
|
|
|
}else {
|
|
|
|
|
var distance = getDistanceFromLatLonInMeters(prevCoords[0], prevCoords[1], latitude, longitude);
|
|
|
|
|
var timeDiff = timestamp - prevTimestamp;
|
|
|
|
|
|
|
|
|
|
if (distance > MAX_DISTANCE && timeDiff < MIN_TIME_DIFF) {
|
|
|
|
|
// Если дистанция слишком большая и прошло меньше допустимого времени, игнорируем это значение
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Обновляем предыдущие координаты и время
|
|
|
|
|
prevCoords = [latitude, longitude];
|
|
|
|
|
prevTimestamp = timestamp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i_Latitude.data.set('content', '<p>Широта: ' + latitude + '</p>');
|
|
|
|
|
i_Longitude.data.set('content', '<p>Долгота: ' + longitude + '</p>');
|
|
|
|
|
i_Altitude.data.set('content', '<p>Высота: ' + altitude + '</p>');
|
|
|
|
|
i_Accuracy.data.set('content', '<p>Точность: ' + accuracy + '</p>');
|
|
|
|
|
i_AltitudeAccuracy.data.set('content', '<p>Точность высоты: ' + altitudeAccuracy + '</p>');
|
|
|
|
|
i_Heading.data.set('content', '<p>Направление: ' + heading + '</p>');
|
|
|
|
|
i_Speed.data.set('content', '<p>Скорость: ' + speed + '</p>');
|
|
|
|
|
|
|
|
|
|
smoothMoveMarker(marker, {lat: latitude, lng: longitude});
|
|
|
|
|
//smoothRotateMarker(marker, heading);
|
|
|
|
|
|
|
|
|
|
if (firstStep) {
|
|
|
|
|
cameraControl(latitude, longitude, zoom);
|
|
|
|
|
firstStep = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(drawTrack){
|
|
|
|
|
drawingTrack({lat: latitude, lng: longitude});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (followUser) {
|
|
|
|
|
cameraControl(latitude, longitude, zoom);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function geolocationLt(location){
|
|
|
|
|
console.log('geolocationLt','обновление позиции',location);
|
|
|
|
|
// Получаем координаты пользователя и некоторые другие полезные данные
|
|
|
|
|
var latitude = location.coords.latitude;
|
|
|
|
|
var longitude = location.coords.longitude;
|
|
|
|
|
var altitude = location.coords.altitude;
|
|
|
|
|
var accuracy = location.coords.accuracy;
|
|
|
|
|
var altitudeAccuracy = location.coords.altitudeAccuracy;
|
|
|
|
|
var heading = location.coords.heading;
|
|
|
|
|
var speed = location.coords.speed;
|
|
|
|
|
var timestamp = getDate(location.timestamp);
|
|
|
|
|
var zoom = getZoom(speed);
|
|
|
|
|
|
|
|
|
|
if (!prevCoords) {
|
|
|
|
|
prevCoords = [latitude, longitude];
|
|
|
|
|
prevTimestamp = timestamp;
|
|
|
|
|
return;
|
|
|
|
|
}else {
|
|
|
|
|
var distance = getDistanceFromLatLonInMeters(prevCoords[0], prevCoords[1], latitude, longitude);
|
|
|
|
|
var timeDiff = timestamp - prevTimestamp;
|
|
|
|
|
|
|
|
|
|
if (distance > MAX_DISTANCE && timeDiff < MIN_TIME_DIFF) {
|
|
|
|
|
// Если дистанция слишком большая и прошло меньше допустимого времени, игнорируем это значение
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Обновляем предыдущие координаты и время
|
|
|
|
|
prevCoords = [latitude, longitude];
|
|
|
|
|
prevTimestamp = timestamp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i_Latitude.data.set('content', '<p>Широта: ' + latitude + '</p>');
|
|
|
|
|
i_Longitude.data.set('content', '<p>Долгота: ' + longitude + '</p>');
|
|
|
|
|
i_Altitude.data.set('content', '<p>Высота: ' + altitude + '</p>');
|
|
|
|
|
i_Accuracy.data.set('content', '<p>Точность: ' + accuracy + '</p>');
|
|
|
|
|
i_AltitudeAccuracy.data.set('content', '<p>Точность высоты: ' + altitudeAccuracy + '</p>');
|
|
|
|
|
i_Heading.data.set('content', '<p>Направление: ' + heading + '</p>');
|
|
|
|
|
i_Speed.data.set('content', '<p>Скорость: ' + speed + '</p>');
|
|
|
|
|
|
|
|
|
|
smoothMoveMarker(marker, {lat: latitude, lng: longitude});
|
|
|
|
|
//smoothRotateMarker(marker, heading);
|
|
|
|
|
|
|
|
|
|
if (firstStep) {
|
|
|
|
|
cameraControl(latitude, longitude, zoom);
|
|
|
|
|
firstStep = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(drawTrack){
|
|
|
|
|
drawingTrack({lat: latitude, lng: longitude});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (followUser) {
|
|
|
|
|
cameraControl(latitude, longitude, zoom);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function drawingTrack(point){
|
|
|
|
|
track.push([point.lat,point.lng]);
|
|
|
|
|
// Если полилиния еще не создана, создайте ее
|
|
|
|
|
if (!polyline) {
|
|
|
|
|
polyline = new ymaps.Polyline(track, {}, {
|
|
|
|
|
strokeColor: '#2f76e3',
|
|
|
|
|
strokeWidth: 6
|
|
|
|
|
});
|
|
|
|
|
map.geoObjects.add(polyline);
|
|
|
|
|
} else {
|
|
|
|
|
// Обновите геометрию полилинии, если она уже существует
|
|
|
|
|
polyline.geometry.setCoordinates(track);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Плавное перемещение маркера
|
|
|
|
|
function smoothMoveMarker(marker, newPosition) {
|
|
|
|
|
var start = marker.geometry.getCoordinates(),
|
|
|
|
|
end = [newPosition.lat, newPosition.lng],
|
|
|
|
|
duration = 1000, // Продолжительность анимации в миллисекундах
|
|
|
|
|
startTime = new Date().getTime(), // Время начала анимации
|
|
|
|
|
animateMarker = function() {
|
|
|
|
|
var time = new Date().getTime() - startTime,
|
|
|
|
|
percent = time / duration;
|
|
|
|
|
if (percent < 1) {
|
|
|
|
|
var newPosition = [
|
|
|
|
|
start[0] + (end[0] - start[0]) * percent,
|
|
|
|
|
start[1] + (end[1] - start[1]) * percent
|
|
|
|
|
];
|
|
|
|
|
marker.geometry.setCoordinates(newPosition);
|
|
|
|
|
requestAnimationFrame(animateMarker);
|
|
|
|
|
} else {
|
|
|
|
|
marker.geometry.setCoordinates(end);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
animateMarker();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function correctHeading(startHeading, endHeading) {
|
|
|
|
|
var delta = endHeading - startHeading;
|
|
|
|
|
if (delta > 180) {
|
|
|
|
|
delta -= 360;
|
|
|
|
|
} else if (delta < -180) {
|
|
|
|
|
delta += 360;
|
|
|
|
|
}
|
|
|
|
|
return delta;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function smoothRotateMarker(marker, newHeading) {
|
|
|
|
|
//marker.options.set('iconRotate', newHeading);
|
|
|
|
|
var startHeading = marker.options.get('iconRotate'),
|
|
|
|
|
endHeading = newHeading,
|
|
|
|
|
duration = 1000, // Продолжительность анимации в миллисекундах
|
|
|
|
|
startTime = new Date().getTime(), // Время начала анимации
|
|
|
|
|
animateRotation = function() {
|
|
|
|
|
var time = new Date().getTime() - startTime,
|
|
|
|
|
percent = time / duration;
|
|
|
|
|
|
|
|
|
|
// Коррекция угла для плавного вращения
|
|
|
|
|
var delta = correctHeading(startHeading, endHeading);
|
|
|
|
|
|
|
|
|
|
if (percent < 1) {
|
|
|
|
|
var interpolatedHeading = startHeading + delta * percent;
|
|
|
|
|
interpolatedHeading = (interpolatedHeading + 360) % 360;
|
|
|
|
|
|
|
|
|
|
marker.options.set('iconRotate', interpolatedHeading);
|
|
|
|
|
marker.options.set('iconImageOffset', [-16,-16]);
|
|
|
|
|
marker.options.set('iconLayout', ymaps.templateLayoutFactory.createClass(
|
|
|
|
|
/*'<div class="rotating-icon" style="transform: rotate(' + endHeading + 'deg);">' +
|
|
|
|
|
' <img src="img/arrow-icon.svg"/>' +
|
|
|
|
|
'</div>'*/
|
|
|
|
|
'<div class="rotating-icon border border-dark border-2" style="transform:rotate({{options.rotate}}deg);">' +
|
|
|
|
|
' <img src="img/arrow-icon.svg"/>',
|
|
|
|
|
'</div>'
|
|
|
|
|
));
|
|
|
|
|
/*marker.options.set('iconContentLayout', ymaps.templateLayoutFactory.createClass(
|
|
|
|
|
'<div class="rotating-icon" style="transform: rotate(' + interpolatedHeading + 'deg);">' +
|
|
|
|
|
' {% include "default#image" %}',
|
|
|
|
|
'</div>'
|
|
|
|
|
));*/
|
|
|
|
|
/*marker.options.set('rotate', interpolatedHeading);
|
|
|
|
|
marker.options.set('iconContentLayout', ymaps.templateLayoutFactory.createClass(
|
|
|
|
|
'<div class="rotating-icon" style="transform: rotate(' + interpolatedHeading + 'deg);">' +
|
|
|
|
|
' <img src="img/navi-arrow.webp"/>' +
|
|
|
|
|
'</div>'
|
|
|
|
|
));*/
|
|
|
|
|
requestAnimationFrame(animateRotation);
|
|
|
|
|
} else {
|
|
|
|
|
if (endHeading < 0) {
|
|
|
|
|
endHeading += 360;
|
|
|
|
|
} else if (endHeading >= 360) {
|
|
|
|
|
endHeading -= 360;
|
|
|
|
|
}
|
|
|
|
|
marker.options.set('iconRotate', endHeading);
|
|
|
|
|
marker.options.set('iconImageOffset', [-16,-16]);
|
|
|
|
|
marker.options.set('iconLayout', ymaps.templateLayoutFactory.createClass(
|
|
|
|
|
'<div class="rotating-icon border border-dark border-2" style="transform:rotate({{options.rotate}}deg);">' +
|
|
|
|
|
' <img src="img/arrow-icon.svg"/>',
|
|
|
|
|
'</div>'
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
animateRotation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function cameraControl(latitude,longitude, originalZoom){
|
|
|
|
|
var zoom = Math.round(originalZoom);
|
|
|
|
|
map.panTo([latitude, longitude], {
|
|
|
|
|
duration: 1000 // Длительность анимации в миллисекундах
|
|
|
|
|
})
|
|
|
|
|
.then(() => {
|
|
|
|
|
// Устанавливаем зум карты после перемещения
|
|
|
|
|
map.setZoom(zoom, {
|
|
|
|
|
duration: 500 // Длительность анимации в миллисекундах
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getDate(timestamp){
|
|
|
|
|
var date = new Date(timestamp); // преобразуем timestamp в объект Date
|
|
|
|
|
|
|
|
|
|
var day = date.getDate(); // получаем день месяца
|
|
|
|
|
var month = date.getMonth() + 1; // получаем месяц (от 1 до 12)
|
|
|
|
|
var year = date.getFullYear(); // получаем год
|
|
|
|
|
|
|
|
|
|
var hours = date.getHours(); // получаем часы (от 0 до 23)
|
|
|
|
|
var minutes = date.getMinutes(); // получаем минуты (от 0 до 59)
|
|
|
|
|
var seconds = date.getSeconds(); // получаем секунды (от 0 до 59)
|
|
|
|
|
|
|
|
|
|
return day + '.' + month + '.' + year + ' ' + hours + ':' + minutes + ':' + seconds;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function onError(error){
|
|
|
|
|
$('#content').empty();
|
|
|
|
|
$('#content').append(
|
|
|
|
|
'<div class="container">' +
|
|
|
|
|
' <div class="row">' +
|
|
|
|
|
' <div class="col">' +
|
|
|
|
|
' <p class="fs-2 text-dark">Ошибка!</p>' +
|
|
|
|
|
' <p>' + error + '</p>' +
|
|
|
|
|
' </div>' +
|
|
|
|
|
' </div>' +
|
|
|
|
|
'</div>'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function hammerTime(){
|
|
|
|
|
// Initialize Hammer.js for the touch-carousel element
|
|
|
|
|
var touchCarousel = document.querySelector('.touch-carousel');
|
|
|
|
|
var mc = new Hammer(touchCarousel);
|
|
|
|
|
|
|
|
|
|
// Configure Hammer.js to recognize swipe gestures
|
|
|
|
|
mc.get('swipe').set({direction: Hammer.DIRECTION_HORIZONTAL});
|
|
|
|
|
|
|
|
|
|
// Handle swipe left events
|
|
|
|
|
mc.on('swipeleft', function (ev) {
|
|
|
|
|
ev.preventDefault();
|
|
|
|
|
$('#columnsCarousel').carousel('next');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Handle swipe right events
|
|
|
|
|
mc.on('swiperight', function (ev) {
|
|
|
|
|
ev.preventDefault();
|
|
|
|
|
$('#columnsCarousel').carousel('prev');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Handle button clicks
|
|
|
|
|
$('[id^=btn-column-]').click(function (ev) {
|
|
|
|
|
ev.preventDefault();
|
|
|
|
|
var columnIndex = parseInt(this.id.split('-')[2], 10);
|
|
|
|
|
$('#columnsCarousel').carousel(columnIndex - 1);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getZoom(speed){
|
|
|
|
|
var correctSpeed = speed;
|
|
|
|
|
if(correctSpeed > 60){
|
|
|
|
|
correctSpeed = 60;
|
|
|
|
|
}
|
|
|
|
|
if(correctSpeed < 1){
|
|
|
|
|
correctSpeed = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var zoom = 17 - ((correctSpeed / 60) * 17);
|
|
|
|
|
if(zoom < 1){
|
|
|
|
|
zoom = 1;
|
|
|
|
|
}
|
|
|
|
|
if(zoom > 17){
|
|
|
|
|
zoom = 17;
|
|
|
|
|
}
|
|
|
|
|
return zoom;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function showCamera(){
|
|
|
|
|
$(document).ready(function () {
|
|
|
|
|
var footerRow = $('#footerRow');
|
|
|
|
|
var middleCol = $('#middleCol');
|
|
|
|
|
var middleIcon = middleCol.find('.expand');
|
|
|
|
|
|
|
|
|
|
middleCol.removeClass('hidden');
|
|
|
|
|
footerRow.removeClass('row-cols-3').addClass('row-cols-4');
|
|
|
|
|
setTimeout(function () {
|
|
|
|
|
middleIcon.addClass('expanded');
|
|
|
|
|
}, 50); // Добавляем небольшую задержку для активации анимации
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function hideCamera() {
|
|
|
|
|
$(document).ready(function () {
|
|
|
|
|
var footerRow = $('#footerRow');
|
|
|
|
|
var middleCol = $('#middleCol');
|
|
|
|
|
var middleIcon = middleCol.find('.expand');
|
|
|
|
|
|
|
|
|
|
middleIcon.removeClass('expanded');
|
|
|
|
|
setTimeout(function () {
|
|
|
|
|
middleCol.addClass('hidden');
|
|
|
|
|
footerRow.removeClass('row-cols-4').addClass('row-cols-3');
|
|
|
|
|
}, 500); // Добавляем задержку, чтобы завершить анимацию
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function addParkBoundaries(parkName) {
|
|
|
|
|
fetch('borders/' + parkName + '.osm') // Путь к вашему файлу с границами парка Налычево
|
|
|
|
|
.then(response => response.text())
|
|
|
|
|
.then(xmlData => {
|
|
|
|
|
const parkBoundaries = parseOSMData(xmlData);
|
|
|
|
|
// Отображаем границы на карте
|
|
|
|
|
parkBoundaries.forEach(coordinates => {
|
|
|
|
|
// Трансформируем координаты для правильного формата Яндекс.Карт
|
|
|
|
|
const transformedCoordinates = coordinates.map(coord => [coord[1], coord[0]]);
|
|
|
|
|
const parkBoundary = new ymaps.Polyline(
|
|
|
|
|
coordinates,
|
|
|
|
|
{},
|
|
|
|
|
{ strokeColor: "#FF0000", strokeWidth: 2 }
|
|
|
|
|
);
|
|
|
|
|
map.geoObjects.add(parkBoundary);
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
.catch(error => console.error("Ошибка загрузки файла OSM: ", error));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Функция для получения файла или создания нового
|
|
|
|
|
function getFile(dirEntry, fileName) {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
dirEntry.getFile(fileName, { create: true }, resolve, reject);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Функция для чтения содержимого файла
|
|
|
|
|
function readFile(fileEntry) {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
fileEntry.file(file => {
|
|
|
|
|
const reader = new FileReader();
|
|
|
|
|
reader.onloadend = () => resolve(reader.result);
|
|
|
|
|
reader.onerror = reject;
|
|
|
|
|
reader.readAsText(file);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadSavedPhotos() {
|
|
|
|
|
loadData(function(data) {
|
|
|
|
|
console.log('Получены данные: ', data);
|
|
|
|
|
data.forEach(function(photoData){
|
|
|
|
|
addPhotoMarker(photoData);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function startMockGeolocation() {
|
|
|
|
|
var latitude = 37.7749; // Начальные координаты
|
|
|
|
|
var longitude = -122.4194;
|
|
|
|
|
var heading = 0; // Начальное направление
|
|
|
|
|
|
|
|
|
|
watchID = setInterval(function() {
|
|
|
|
|
heading -= 19; // Увеличиваем направление
|
|
|
|
|
if (heading >= 360) {
|
|
|
|
|
heading = 0;
|
|
|
|
|
}
|
|
|
|
|
if(heading < 0){
|
|
|
|
|
heading = 360;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var position = {
|
|
|
|
|
coords: {
|
|
|
|
|
latitude: latitude,
|
|
|
|
|
longitude: longitude,
|
|
|
|
|
altitude: null,
|
|
|
|
|
accuracy: 10,
|
|
|
|
|
altitudeAccuracy: null,
|
|
|
|
|
heading: heading,
|
|
|
|
|
speed: 0.0001
|
|
|
|
|
},
|
|
|
|
|
timestamp: Date.now()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Вызываем ваш onSuccess метод с фейковыми данными
|
|
|
|
|
onSuccess(position);
|
|
|
|
|
|
|
|
|
|
// Меняем координаты для следующего вызова
|
|
|
|
|
latitude += 0.0001;
|
|
|
|
|
longitude += 0.0001;
|
|
|
|
|
}, 1000); // Обновляем каждую секунду
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function stopMockGeolocation() {
|
|
|
|
|
clearInterval(watchID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function generateUUID() {
|
|
|
|
|
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
|
|
|
|
|
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-16 14:36:58 +00:00
|
|
|
|
//loadMapNalychevoOnePage();
|
2024-06-16 12:12:20 +00:00
|
|
|
|
|