614 lines
18 KiB
JavaScript
614 lines
18 KiB
JavaScript
/*
|
||
* 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;
|
||
|
||
// -------------------------------- Libs ---------------------------------------
|
||
|
||
function getURLParameter(name) {
|
||
return decodeURI((RegExp(name + '=' + '(.+?)(&|$)').exec(location.search) || [, null])[1]);
|
||
}
|
||
|
||
// -----------------------------------------------------------------------------
|
||
|
||
/**
|
||
* Инициализируем переменные и подгружаем данные.
|
||
* @returns true
|
||
*/
|
||
function init() {
|
||
myMap = L.map('map').setView([51.505, -0.09], 13);
|
||
L.tileLayer('http://otile1.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png', {
|
||
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>',
|
||
maxZoom: 18
|
||
}).addTo(myMap);
|
||
|
||
//
|
||
// questLayer = function () {
|
||
// return new ymaps.Layer(
|
||
// 'http://otile1.mqcdn.com/tiles/1.0.0/osm/%z/%x/%y.png', {projection: ymaps.projection.sphericalMercator});
|
||
// };
|
||
// ymaps.layer.storage.add('quest#layer', questLayer);
|
||
// ymaps.mapType.storage.add('quest#type', new ymaps.MapType('MapQuest', ['quest#layer']));
|
||
//
|
||
// osmLayer = function () {
|
||
// return new ymaps.Layer(
|
||
// 'http://c.tile.openstreetmap.org/%z/%x/%y.png', {projection: ymaps.projection.sphericalMercator});
|
||
// };
|
||
// ymaps.layer.storage.add('osm#layer', osmLayer);
|
||
// ymaps.mapType.storage.add('osm#type', new ymaps.MapType('OpenStreetMap', ['osm#layer']));
|
||
//
|
||
// googleLayer = function () {
|
||
// return new ymaps.Layer('http://mt0.google.com/vt/lyrs=s@176000000&hl=ru&%c', {projection: ymaps.projection.sphericalMercator,tileTransparent: true});
|
||
// }
|
||
// ymaps.layer.storage.add('google#layer', googleLayer);
|
||
// ymaps.mapType.storage.add('google#type', new ymaps.MapType('Google Maps', ['google#layer']));
|
||
//
|
||
// myMap = new ymaps.Map("map", {
|
||
// center: [ymaps.geolocation.latitude, ymaps.geolocation.longitude],
|
||
// zoom: 12,
|
||
// type:'quest#type',
|
||
// behaviors: ['default', 'scrollZoom']
|
||
// });
|
||
//
|
||
// myMap.controls.add('mapTools');
|
||
// myMap.controls.add('smallZoomControl');
|
||
// myMap.controls.add('scaleLine');
|
||
//
|
||
// typeSelector = new ymaps.control.TypeSelector();
|
||
// typeSelector.addMapType('quest#type', 0);
|
||
// typeSelector.addMapType('google#type', 1);
|
||
// typeSelector.addMapType('yandex#publicMap', 2);
|
||
// typeSelector.addMapType('osm#type', 3);
|
||
// myMap.controls.add(typeSelector);
|
||
// myMap.copyrights.add('Участники <a href="http://www.openstreetmap.org/copyright" target="blank">OpenStreetMap</a>');
|
||
// myMap.copyrights.add('Tiles courtesy of <a href="http://www.mapquest.com/" target="blank">MapQuest</a>');
|
||
|
||
initCategories()
|
||
// getPoints();
|
||
|
||
// myMap.events.add('click', function(e) {
|
||
// if (!myMap.balloon.isOpen()) {
|
||
// if (status == statusHunting)
|
||
// {
|
||
// coords = e.get('coordPosition');
|
||
//
|
||
// $('#addPointId').remove();
|
||
// $('#addPointForm input').val('');
|
||
// $("#addPointCategoryId option" ).attr('selected', null);
|
||
// $('#addPointLat').val(coords[0].toPrecision(11));
|
||
// $('#addPointLng').val(coords[1].toPrecision(11));
|
||
//
|
||
// $('#myModalLabel').text('Добавление новой точки');
|
||
// $('#addPointModal').modal('show');
|
||
// } else if (status == statusReHunting)
|
||
// {
|
||
// resetStatus();
|
||
// coords = e.get('coordPosition');
|
||
//
|
||
// $('#addPointLat').val(coords[0].toPrecision(11));
|
||
// $('#addPointLng').val(coords[1].toPrecision(11));
|
||
//
|
||
// $('#myModalLabel').text('Редактирование точки');
|
||
// $('#addPointModal').modal('show');
|
||
// }
|
||
// }
|
||
// else {
|
||
// myMap.balloon.close();
|
||
// }
|
||
// });
|
||
//
|
||
// myMap.events.add('boundschange', function(e) {
|
||
// if (!myMap.balloon.isOpen() && $('#routeWindow').css('display') == 'none')
|
||
// {
|
||
// history.pushState({}, document.title, "/?lat=" + e.get('newCenter')[0] + "&lng=" + e.get('newCenter')[1] + "&zoom=" + e.get('newZoom'));
|
||
// }
|
||
// });
|
||
//
|
||
// points.im = new ymaps.Placemark(
|
||
// [ymaps.geolocation.latitude, ymaps.geolocation.longitude],
|
||
// {
|
||
// balloonContentHeader: 'Вы здесь',
|
||
// hintContent: 'Ваше местоположение',
|
||
// balloonContent:
|
||
// '<button type="button" class="btn btn-default btn-xs" onclick="addToRoute(\'im\')">' +
|
||
// '<span class="glyphicon glyphicon-plus"></span> Добавить в маршрут' +
|
||
// '</button>'
|
||
// },
|
||
// {
|
||
// 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 && $('#routeWindow').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 = '<div class="infoCard">' +
|
||
'<h3>' + data.name + '</h3>' +
|
||
'<img src="' + data.img + '" />' +
|
||
'<button type="button" class="btn btn-default btn-xs" onclick="addToRoute(' + id + ')">' +
|
||
'<span class="glyphicon glyphicon-plus"></span> Добавить в маршрут' +
|
||
'</button><br/>';
|
||
|
||
if (isAdmin == '1')
|
||
{
|
||
description = description + '<button type="button" class="btn btn-default btn-xs" onclick="editPoint(' + id + ')">' +
|
||
'<span class="glyphicon glyphicon-pencil"></span> Редактировать' +
|
||
'</button><br/>';
|
||
}
|
||
|
||
description = description + data.descriptionHtml;
|
||
|
||
if (data.source.length > 11)
|
||
description = description + ' <a href="' + data.source + '" target="blank">Подробнее...</a>';
|
||
|
||
description = description + '</div>';
|
||
|
||
marker.options.description = description;
|
||
marker.bindPopup(marker.options.description, {maxWidth: 500}).openPopup();
|
||
}
|
||
});
|
||
}
|
||
|
||
history.pushState({}, document.title, "/?point=" + id);
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Загружает с сервера список категорий точек.
|
||
* @returns {Boolean}
|
||
*/
|
||
function initCategories()
|
||
{
|
||
$.ajax({
|
||
url: "/json/categories/",
|
||
success: function(data) {
|
||
//categories = 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()
|
||
{
|
||
var myGeocoder = ymaps.geocode($('#addressField').val());
|
||
myGeocoder.then(
|
||
function(res) {
|
||
search = new ymaps.Placemark(res.geoObjects.get(0).geometry.getCoordinates());
|
||
myMap.geoObjects.add(search);
|
||
myMap.setCenter(res.geoObjects.get(0).geometry.getCoordinates(), 10);
|
||
},
|
||
function(err) {
|
||
}
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Пытается более точно определить координаты пользователя на карте и, при необходимости, обновляет положение точки "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('btn-success').toggleClass('btn-default');
|
||
if ($('#addPointButton').hasClass('btn-success'))
|
||
{
|
||
myMap.cursors.push('crosshair');
|
||
setStatus(statusHunting)
|
||
}
|
||
else
|
||
{
|
||
myMap.cursors.push('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.geoObjects.remove(points[id]);
|
||
}
|
||
|
||
balloon = myMap.balloon.open([$('#addPointLat').val(), $('#addPointLng').val()], {content: text}, {closeButton: false});
|
||
setTimeout(function() {
|
||
balloon.close();
|
||
}, 2000);
|
||
|
||
obj = {};
|
||
obj.id = data;
|
||
obj.name = $('#addPointName').val();
|
||
obj.lat = $('#addPointLat').val();
|
||
obj.lng = $('#addPointLng').val();
|
||
obj.categoryIcon = categories[$('#addPointCategoryId').val()].icon;
|
||
|
||
setTimeout(function() {
|
||
myMap.geoObjects.add(constructPoint(obj));
|
||
}, 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();
|
||
myMap.cursors.push('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)
|
||
{
|
||
$('#wayPoints').append('<div pointid="' + id + '" class="wayPoint"><span onclick="$(this).parent().remove()">×</span> ' + points[id].properties.get('hintContent') + '</div>');
|
||
myMap.balloon.close();
|
||
$('#routeWindow').show(200);
|
||
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();
|
||
$('<input type="hidden" id="addPointId" name="id"/>').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.balloon.close();
|
||
$('#addPointModal').modal('show');
|
||
setStatus(statusEdit);
|
||
}
|
||
|
||
function editSetNewCoords()
|
||
{
|
||
$('#addPointModal').modal('hide');
|
||
myMap.cursors.push('crosshair');
|
||
setStatus(statusReHunting)
|
||
}
|