/*
* Let's GO!
*/
// ------------ Система статусов приложения ------------------------------------
var statusReady = 0; // Обычный режим. Просмотр точек, навигация по карте и прочее.
var statusHunting = 1; // Курсор-прицел. Поиск места для добавления точки.
var statusReHunting = 2; // КУрсор прицел. Переопределение координат точки.
var statusAdd = 3; // Открыто окно добавления точки - форма.
var statusEdit = 4; // Открыто окно редактирования точки. В нём информация о существующей точке, включая ID.
var statusSendingToServer = 5; // Отправлен запрос на сервер - ждём, не даём жать кнопку повторно, отвлекаем пользователя.
var status = statusReady;
var statusPrev = statusReady;
/**
* Устанавливает новое значение статуса.
* @returns {undefined}
*/
function setStatus(value)
{
statusPrev = status;
status = value;
}
/**
* Меняет значение статуса на предыдущее.
* @returns {undefined}
*/
function resetStatus()
{
tmp = status;
status = statusPrev;
statusPrev = tmp;
}
// -----------------------------------------------------------------------------
$(document).ready(function(){init()});
var myMap;
var categories = Array();
var points = Array();
var pointsSources = Array();
var search;
var route = false;
var addPointInProcess = false;
var layer;
var layers = Array();
// -------------------------------- Libs ---------------------------------------
function getURLParameter(name) {
return decodeURI((RegExp(name + '=' + '(.+?)(&|$)').exec(location.search) || [, null])[1]);
}
// -----------------------------------------------------------------------------
/**
* Инициализируем переменные и подгружаем данные.
* @returns true
*/
function init() {
myMap = L.map('map',{zoomControl: false}).setView([57, 30], 4);
layers['quest'] = L.tileLayer('http://otile1.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png', {attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © Mapbox',maxZoom: 18});
layers['osm'] = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery ©',maxZoom: 18});
layers['google'] = new L.Google('HYBRID');
layers['yandexMap'] = new L.Yandex();
layers['yandex'] = new L.Yandex('hybrid');
setLayer('quest');
initCategories(); // getPoints внутри
myMap.on('click', function(e) {
if (!myMap._popup) {
if (status == statusHunting)
{
$('#addPointId').remove();
$('#addPointForm input').val('');
$("#addPointCategoryId option" ).attr('selected', null);
$('#addPointLat').val(e.latlng.lat);
$('#addPointLng').val(e.latlng.lng);
$('#myModalLabel').text('Добавление новой точки');
$('#addPointModal').modal('show');
} else if (status == statusReHunting)
{
resetStatus();
$('#addPointLat').val(e.latlng.lat);
$('#addPointLng').val(e.latlng.lng);
$('#myModalLabel').text('Редактирование точки');
$('#addPointModal').modal('show');
}
}
else {
myMap._popup._close();
}
});
// points.im = new ymaps.Placemark(
// [ymaps.geolocation.latitude, ymaps.geolocation.longitude],
// {
// balloonContentHeader: 'Вы здесь',
// hintContent: 'Ваше местоположение',
// balloonContent:
// ''
// },
// {
// iconImageHref: '/ico/man.png',
// iconImageSize: [32, 37],
// iconImageOffset: [-16, -33],
// }
// );
// myMap.geoObjects.add(points.im);
$("#wayPoints").sortable();
$("#wayPoints").disableSelection();
myMap.on('moveend', function(e) {
if (!myMap._popup && $('#boxRoute').css('display') == 'none')
{
history.pushState({}, document.title, "/?lat=" + myMap.getCenter().lat + "&lng=" + myMap.getCenter().lng + "&zoom=" + myMap.getZoom());
}
});
return true;
}
/**
* Создаёт точку для карту - Placemark.
* @param {Array} data
* @returns {ymaps.Placemark}
*/
function constructPoint(data)
{
id = data['id'];
points[id] = L.marker(
[data['lat'], data['lng']], {icon: categories[data['categoryId']], title: data['name'],id: id}
).on('click', function(e){showInfo(e.target.options.id);});
return points[id];
}
/**
* Загружает точки с сервера.
* @returns {Boolean}
*/
function getPoints()
{
$.ajax({
url: "/json/points/",
success: function(data) {
for (var k in data) {
constructPoint(data[k]).addTo(myMap);
}
if (getURLParameter('point') != 'null')
{
showInfo(getURLParameter('point'));
} else if (getURLParameter('route') != 'null')
{
loadRouteJSON(getURLParameter('route'));
buildRoute();
} else if ((getURLParameter('lat') != 'null') && (getURLParameter('lng') != 'null') && (getURLParameter('zoom') != 'null'))
{
myMap.setView([getURLParameter('lat'), getURLParameter('lng')], getURLParameter('zoom'));
}
}
});
return true;
}
/**
* Показывает баллун для точки. Если данных для точки нет, то подгружает их с сервера.
* @param {type} id
* @returns {Boolean}
*/
function showInfo(id)
{
marker = points[id];
if (!(id in points) || marker.options.description == undefined)
{
marker.bindPopup("Загрузка...").openPopup();
$.ajax({
url: "/json/point/id/" + id,
success: function(data) {
pointsSources[id] = data;
description = '
' +
'
' + data.name + '
' +
'

' +
'
';
if (isAdmin == '1')
{
description = description + '
';
}
description = description + data.descriptionHtml;
if (data.source.length > 11)
description = description + '
Подробнее...';
description = description + '
';
marker.options.description = description;
marker.bindPopup(marker.options.description, {maxWidth: 500, maxHeight: 300}).openPopup();
}
});
}
history.pushState({}, document.title, "/?point=" + id);
return true;
}
/**
* Загружает с сервера список категорий точек.
* @returns {Boolean}
*/
function initCategories()
{
$.ajax({
url: "/json/categories/",
success: function(data) {
for (var k in data) {
categories[data[k]['id']] = L.icon({
iconUrl: data[k]['icon'],
iconSize: [32, 37], // size of the icon
iconAnchor: [16, 37], // point of the icon which will correspond to marker's location
popupAnchor: [0, 1] // point from which the popup should open relative to the iconAnchor
});
}
getPoints();
}
});
return true;
}
/**
* Производит поиск по адресу или координатам, введённым в соответствующее поле.
* @returns {undefined}
*/
function searchAdderess()
{
$.ajax({
url: "/json/geocoding",
data: {
search: $('#addressField').val()
},
success: function(data)
{
if (data.lat && data.lng)
{
myMap.setView([data.lat, data.lng], 13);
L.popup()
.setLatLng([data.lat, data.lng])
.setContent('Координаты: lat:'+data.lat+' lng:'+data.lng)
.openOn(myMap);
} else
{
alert('Ничего не найдено.');
}
}
});
}
/**
* Пытается более точно определить координаты пользователя на карте и, при необходимости, обновляет положение точки "im"
* @returns {undefined}
*/
function showMeOnTheMap()
{
navigator.geolocation.getCurrentPosition(function(pos) {
points.im.geometry.setCoordinates([pos.coords.latitude, pos.coords.longitude]);
myMap.setCenter(points.im.geometry.getCoordinates());
});
myMap.setCenter(points.im.geometry.getCoordinates());
}
/**
* Активирет добавление точки - ждёт выбор координат, меняет курсор на прицел.
* @returns {Boolean}
*/
function activateAddPoint()
{
$('#addPointButton').toggleClass('active');
if ($('#addPointButton').hasClass('active'))
{
$('#map').css('cursor', 'crosshair');
setStatus(statusHunting)
}
else
{
$('#map').css('cursor', 'arrow');
setStatus(statusReady)
}
return true;
}
/**
* Отправляет данные о точке на сервер.
* @returns {Boolean}
*/
function addPoint()
{
$('.form-group').removeClass('has-error');
if (status != statusSendingToServer)
{
setStatus(statusSendingToServer)
id = $('#addPointId').length ? $('#addPointId').val() : 0;
$.ajax({
type: "POST",
url: "/json/addpoint/",
data: {
name: $('#addPointName').val(),
img: $('#addPointImg').val(),
description: $('#addPointDescription').val(),
categoryId: $('#addPointCategoryId').val(),
source: $('#addPointSource').val(),
lat: $('#addPointLat').val(),
lng: $('#addPointLng').val(),
id: id
},
success: function(data) {
text = id ? 'Точка успешно отредактирована!' : 'Точка успешно добавлена!';
if ( id )
{
myMap.removeLayer(points[id]);
}
balloon = L.popup()
.setLatLng([$('#addPointLat').val(), $('#addPointLng').val()])
.setContent(text)
.openOn(myMap);
setTimeout(function() {
balloon._close();
delete balloon;
}, 2000);
obj = {};
obj.id = data;
obj.name = $('#addPointName').val();
obj.lat = $('#addPointLat').val();
obj.lng = $('#addPointLng').val();
obj.categoryIcon = categories[$('#addPointCategoryId').val()].icon;
obj.categoryId = $('#addPointCategoryId').val();
setTimeout(function() {
constructPoint(obj).addTo(myMap);
}, 2000);
$('#addPointModal').modal('hide');
// Clear form
$('#addPointForm input').val('');
$('#addPointForm textarea').val('');
$('.form-group').removeClass('has-error');
$('#addPointButton').removeClass('btn-success').addClass('btn-default');
$('#addPointId').remove();
$('#map').css('cursor', 'arrow');
setStatus(statusReady);
return true;
},
error: function(data) {
response = data.responseJSON;
message = '';
for (var k in response) {
if (typeof response[k] !== 'function') {
if (k == 1)
$('#addPointName').parent().addClass('has-error');
else
if (k == 2)
$('#addPointImg').parent().addClass('has-error');
else
if (k == 3)
$('#addPointDescription').parent().addClass('has-error');
else
message += response[k] + '; ';
}
}
if (message != '')
alert(message);
resetStatus();
return false;
}
});
}
else
{
alert ('Точка добавляется, нужно немного подождать.');
}
}
/**
* Строит маршрут по выбранным точкам.
* @returns {undefined}
*/
function buildRoute()
{
wayPoints = Array();
if (route)
myMap.geoObjects.remove(route);
$('#wayPoints div').each(function(i, el)
{
wayPoints.push(points[$(el).attr('pointId')].geometry.getCoordinates());
});
ymaps.route(wayPoints, {
mapStateAutoApply: true
}).then(function(newRoute) {
route = newRoute;
route.options.set({
// в балуне выводим только информацию о времени движения с учетом пробок
balloonContenBodyLayout: ymaps.templateLayoutFactory.createClass('$[properties.humanJamsTime]'),
strokeColor: '9000ffff',
opacity: 0.9
});
myMap.geoObjects.add(route);
distance = Math.round(route.getLength() / 1000);
$('#routeDistance').text(distance + ' км.');
routeToURL();
});
}
/**
* Сохраняет маршрут на сервере.
* @returns {undefined}
*/
function saveRoute()
{
wayPoints = Array();
name = prompt('Как назвать маршрут?', 'Мой маршрут');
$('#wayPoints div').each(function(i, el)
{
wayPoints.push($(el).attr('pointId'));
});
if (name && name != '')
$.ajax({
type: "POST",
url: "/json/saveroute/",
data: {
name: name,
points: wayPoints
},
success: function(data) {
console.log(data);
},
error: function(data) {
console.log(data);
}
});
}
/**
* Формирует список точек маршрута из JSON.ы
* @param {JSON} data
* @returns {Boolean}
*/
function loadRouteJSON(data)
{
$('#wayPoints').text('');
response = JSON.parse(data);
for (var k in response)
{
addToRoute(response[k]);
}
return true;
}
/**
* Подгружает маршрут с заданныи ID с сервера.
* @param {Integer} id
* @returns {undefined}
*/
function loadRoute(id)
{
$('#myRoutesWindow').hide(200);
$.ajax({
url: "/json/route/id/" + id,
success: function(data)
{
loadRouteJSON(data)
buildRoute();
}
});
}
/**
* Удаляет маршрут с заданным ID с сервера.
* @param {Integer} id
* @returns {undefined}
*/
function deleteRoute(id)
{
$.ajax({
url: "/json/deleteroute/id/" + id,
success: function(data)
{
console.log('Route '+id+' was removed.');
}
});
}
/**
* Добавляет точку с маршрут (в список выбранных точек)
* @param {Integer} id
* @returns {Boolean}
*/
function addToRoute(id)
{
console.log(points[id]);
$('#wayPoints').append('× ' + points[id].options.title + '
');
myMap._popup._close();
openBox('Route', true);
return true;
}
/**
* Формирует URL в соответсвии с точками маршрута.
* @returns {Boolean}
*/
function routeToURL()
{
wayPoints = Array();
$('#wayPoints div').each(function(i, el)
{
wayPoints.push($(el).attr('pointId'));
});
history.pushState({}, document.title, "/?route=" + JSON.stringify(wayPoints));
return true;
}
function editPoint(id)
{
$('#addPointId').remove();
$('').appendTo('#addPointForm').val(id);
$('#addPointName').val(pointsSources[id].name);
$('#addPointImg').val(pointsSources[id].img);
$('#addPointDescription').val(pointsSources[id].description);
$("#addPointCategoryId option" ).attr('selected', null);
$("#addPointCategoryId option[value='"+pointsSources[id].categoryId+"']" ).attr('selected', 'selected');
$('#addPointSource').val(pointsSources[id].source);
$('#addPointLat').val(pointsSources[id].lat);
$('#addPointLng').val(pointsSources[id].lng);
myMap._popup._close();
$('#addPointModal').modal('show');
setStatus(statusEdit);
}
function editSetNewCoords()
{
$('#addPointModal').modal('hide');
$('#map').css('cursor', 'crosshair');
setStatus(statusReHunting)
}
function openBox(type, keepOpen)
{
newTab = $('#box'+type).css('display') == 'none';
keepOpen = keepOpen == true;
if (!newTab && !keepOpen)
{
return closeBox();
}
$('div','#control').removeClass('active');
$('#box').children('div').css('display', 'none');
$('.boxButton'+type).addClass('active');
$('#box'+type).css('display', 'block');
$('body').addClass('openBox');
}
function closeBox()
{
$('body').removeClass('openBox');
$('div','#control').removeClass('active');
$('#box').children('div').css('display', 'none');
return true;
}
function setLayer(name)
{
if (layer)
myMap.removeLayer(layers[layer])
layer = name;
myMap.addLayer(layers[layer]);
$('.layers').removeClass('selected');
$('.'+layer+'Layer').addClass('selected');
}