/* * 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',{zoomControl: false}).setView([51.505, -0.09], 13); 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 }).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('Участники OpenStreetMap'); // myMap.copyrights.add('Tiles courtesy of MapQuest'); 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() { 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('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; }