// Current map variable Map var map; // Current path variable Polyline var poly; // Current markers variable MVCArray var markers; var notifier; // Map initialize function initMap() { map = new google.maps.Map( document.getElementById('map'), { zoom : 15, center : { lat : 50.403757, lng : 30.641328 } } ); createNotifier(map); poly = new google.maps.Polyline( { strokeColor : '#000000', strokeOpacity : 1.0, strokeWeight : 3 } ); poly.setMap(map); markers = new google.maps.MVCArray(); } /** * Map click handler * * @param event google.maps.LatLng */ function addLatLng(event) { var path = poly.getPath(); path.push(event.latLng); var marker = new google.maps.Marker( { position : event.latLng, title : '#' + path.getLength(), map : map, draggable : true, label : path.getLength().toString(10) } ); markers.push(marker); var passport_id = $('#passport_control').data('passport_id'); addMarkerToPassport(passport_id, road_passports[passport_id].getLength(), event.latLng); marker.addListener('dragend', dragend); } function addAt(event) { var index = parseInt(map.lastIndex); var passport_id = $('#passport_control').data('passport_id'); reCalc(index - 1, 1); addMarkerToPassport(passport_id, index, event.latLng); reCalcucaleDistance(passport_id, index + 1); createMarkers(passport_id); google.maps.event.clearListeners(map, 'click'); map.addListener('click', addLatLng); hideNotifier(true); } /** * Fill road passport and table with new element * * @param passport_id integer Road passport ID * @param index integer Poisition in path * @param latLng LatLng object */ function addMarkerToPassport(passport_id, index, latLng) { var object = createPassportObject(); object.lat = latLng.lat(); object.lng = latLng.lng(); object.num = index; object.road_passport_id = passport_id; if(index <= 1 && road_passports[passport_id].model.begin) { object.km = road_passports[passport_id].model.begin; } else { var prev = road_passports[passport_id].getAt(index - 1); object.km = (calculateDistance( new google.maps.LatLng( { lat : parseFloat(prev.lat), lng : parseFloat(prev.lng) } ), latLng ) + parseFloat(prev.km)).toFixed(3); } road_passports[passport_id].insertAt(index, object); addRow(passport_id, index, latLng, object.km); } /** * Dragend event handler: repaint curve and update row * * @param event google.maps.LatLng */ function dragend(event) { var index = parseInt(this.label); repaint(event); updateRow( index, { lat : event.latLng.lat(), lng : event.latLng.lng() } ); } /** * Add row to ( the end of ) the table * * @param passport_id integer Road passport ID * @param index integer New row num * @param latLng LatLng object of new point */ function addRow(passport_id, index, latLng, km) { $.get( template_url, { road_passport_id : passport_id, lat : latLng.lat(), lng : latLng.lng(), num : index, km : km }, function(data) { if(!data.error) { var container = $('#passport_control'); var target = $(container).find('.passport_point_item[data-key=' + (index + 1) + ']'); if(target.length > 0) { $(target).before(data.result.html); } else { $(container).append(data.result.html); } } else { } } ); } /** * Repaint path from current markers * * @param event */ function repaint(event) { var path = new google.maps.MVCArray(); markers.forEach( function(element, index) { path.push(element.getPosition()); } ); poly.setPath(path); } /** * Clear all current markers */ function clearMarkers() { markers.forEach( function(element, index) { element.setMap(null); } ); markers = new google.maps.MVCArray(); } /** * Create empty object for road passport point * * @returns {{km: null, lat: null, lng: null, num: null, point_id: null, road_passport_id: null}} */ function createPassportObject() { return { km : null, lat : null, lng : null, num : null, point_id : null, road_passport_id : null }; } /** * Create empty object for road passport model */ function createPassportModel() { return { begin : null, end : null, region_id : null, road_id : null, road_passport_id : null, }; } /** * Replace all rows starting with @start param on @indent rows * * @param start * @param indent */ function reCalc(start, indent) { var container = $('#passport_control'); var passport_id = parseInt($(container).data('passport_id')); if(start > 0) { elements = $(container).find('[data-key=' + start + '] ~ [data-key]'); } else { elements = $(container).find('[data-key]'); } var old_name; var new_name; var old_id; var new_id; $.each( elements, function(index, value) { var old_index = $(value).data('key'); var new_index = old_index + indent; $(value).attr('data-key', new_index); $(value).data('key', new_index); $(value).find('.point_num_value').text(new_index); $.each( $(value).find('input'), function(i, v) { old_name = $(v).attr('name'); new_name = old_name.replace(/Point\[\d+\]/, 'Point[' + new_index + ']'); $(v).attr('name', new_name); old_id = $(v).attr('id'); new_id = old_id.replace(/point-\d+/, 'point-' + new_index); $(v).attr('id', new_id); } ); $(value).find('input[name="Point[' + new_index + '][num]"]').val(new_index); $(value).find('input[name="Point[' + new_index + '][km]"]').val(NaN); $(value).find('.point-menu>a').attr('href', '#pointControl' + new_index); $(value).find('.point-menu>a').attr('aria-controls', 'pointControl' + new_index); $(value).find('.point_control').attr('id', 'pointControl' + new_index); } ); } /** * Update @index's row with new @data * Supported data: * * lat * * lng * * @param index integer * @param data object */ function updateRow(index, data) { index = parseInt(index); var container = $('#passport_control'); var passport_id = parseInt($(container).data('passport_id')); var element = $(container).find('[data-key=' + index + ']'); if(data.lat) { $(element).find('#point-' + index + '-lat').val(data.lat); road_passports[passport_id].getAt(index).lat = data.lat; } if(data.lng) { $(element).find('#point-' + index + '-lng').val(data.lng); road_passports[passport_id].getAt(index).lng = data.lng; } if(index <= 1) { var km; km = road_passports[passport_id].model.begin; road_passports[passport_id].getAt(index).km = km; $('#point-' + index + '-km').val(km); reCalcucaleDistance(passport_id, index + 1); } else { if(data.km) { $(element).find('#point-' + index + '-km').val(data.km); road_passports[passport_id].getAt(index).km = data.km; reCalcucaleDistance(passport_id, index + 1); } else { reCalcucaleDistance(passport_id, index); } } } /** * Calculate distance between tow LatLng points * * @param LatLngA LatLng * @param LatLngB LatLng * @returns integer */ function calculateDistance(LatLngA, LatLngB) { return parseFloat((google.maps.geometry.spherical.computeDistanceBetween(LatLngA, LatLngB) / 1000).toFixed(3)); } /** * Fill current markers variable with markers for @passport_id * * @param passport_id int Road passport ID */ function createMarkers(passport_id) { clearMarkers(); road_passports[passport_id].forEach( function(element, index) { if(element !== undefined) { var marker = new google.maps.Marker( { position : { lat : parseFloat(element.lat), lng : parseFloat(element.lng) }, title : '#' + parseInt(index), map : map, draggable : true, label : parseInt(index).toString(10) } ); markers.push(marker); marker.addListener('dragend', dragend); repaint(); } } ); } function deleteRow(passport_id, index) { index = parseInt(index); var container = $('#passport_control'); var element = $(container).find('.passport_point_item[data-key=' + index + ']'); reCalc(index, -1); $(element).remove(); road_passports[passport_id].removeAt(index); updateRow(index, {}); reCalcucaleDistance(passport_id, index + 1); createMarkers(passport_id); repaint(); } function showMap() { var body = $('html, body'); var coords = getMapCoords(); body.stop().animate({scrollTop : (coords.top - 50)}, 2000, 'swing'); } function getMapCoords() { var container = map.getDiv(); return $(container).offset(); } function createNotifier(map) { var container = document.createElement('div'); container.id = 'map_notifier'; container.style.display = 'none'; var wrapper = document.createElement('div'); wrapper.style.backgroundColor = '#fff'; wrapper.style.border = '2px solid #fff'; wrapper.style.borderRadius = '3px'; wrapper.style.boxShadow = '0 2px 6px rgba(0,0,0,.3)'; wrapper.style.cursor = 'pointer'; wrapper.style.marginBottom = '22px'; wrapper.style.textAlign = 'center'; container.appendChild(wrapper); // Set CSS for the control interior. var text = document.createElement('div'); text.style.color = 'rgb(25,25,25)'; text.style.fontFamily = 'Roboto,Arial,sans-serif'; text.style.fontSize = '16px'; text.style.lineHeight = '38px'; text.style.paddingLeft = '5px'; text.style.paddingRight = '5px'; text.className = 'map_notifier_text'; wrapper.appendChild(text); container.index = 1; map.controls[google.maps.ControlPosition.TOP_CENTER].push(container); } function showNotifier(message) { var container = $('#map_notifier'); if(message) { setNotifier(message); } $(container).show(); } function hideNotifier(clear) { var container = $('#map_notifier'); $(container).hide(); if(clear) { setNotifier(''); } } function setNotifier(message) { var container = $('#map_notifier'); var text = $(container).find('.map_notifier_text'); $(text).text(message); } function fillPassportModel(passport_id, data) { passport_id = parseInt(passport_id); if(!road_passports[passport_id]) { return false; } if(data.begin) { road_passports[passport_id].model.begin = parseFloat(data.begin); } if(data.end) { road_passports[passport_id].model.end = parseFloat(data.end); } if(data.region_id) { road_passports[passport_id].model.region_id = parseFloat(data.region_id); } if(data.road_id) { road_passports[passport_id].model.road_id = parseFloat(data.road_id); } if(data.road_passport_id) { road_passports[passport_id].model.road_passport_id = parseFloat(data.road_passport_id); } return true; } function reCalcucaleDistance(passport_id, start) { start = parseInt(start); var passport = road_passports[passport_id]; var prev; var next; for(var i = start; i < passport.getLength(); i++) { prev = passport.getAt(i - 1); next = passport.getAt(i); next.km = (calculateDistance( new google.maps.LatLng( { lat : parseFloat(prev.lat), lng : parseFloat(prev.lng) } ), new google.maps.LatLng( { lat : parseFloat(next.lat), lng : parseFloat(next.lng) } ) ) + parseFloat(prev.km)).toFixed(3); road_passports[passport_id].setAt(i, next); $('#point-' + i + '-km').val(next.km); } } function fitBounds() { var bounds = new google.maps.LatLngBounds(); for(var i = 0; i < markers.getLength(); i++) { bounds.extend(markers.getAt(i).getPosition()); } map.fitBounds(bounds); } // var placeIdArray = []; // var polylines = []; // var snappedCoordinates = []; function runSnapToRoad() { var id = $('#passport_control').data('passport_id'); id = parseInt(id); if(!markers.length) { return false; } var pathValues = []; for(var i = 0; i < markers.length; i++) { pathValues.push(markers.getAt(i).getPosition().toUrlValue()); } $.get( '/frontend/web/point/snap', { path : pathValues.join('|'), road_passport_id : id }, function(data) { $('#control').empty().append(data.result.html); road_passports[id] = new google.maps.MVCArray(); if(data.result.passport) { road_passports[id].model = createPassportModel(); fillPassportModel(id, data.result.passport); } road_passports[id].setAt(0, undefined); clearMarkers(); $.each( data.result.points, function(index, value) { road_passports[id].setAt(index, value); var marker = new google.maps.Marker( { position : { lat : parseFloat(value.lat), lng : parseFloat(value.lng) }, title : '#' + parseInt(value.num), map : map, draggable : true, label : parseInt(value.num).toString(10) } ); markers.push(marker); marker.addListener('dragend', dragend); } ); repaint(); fitBounds(); reCalcucaleDistance(id, 2); } ); // $.get('https://roads.googleapis.com/v1/snapToRoads', { // interpolate: true, // key: apiKey, // path: pathValues.join('|') // }, function(data) { // processSnapToRoadResponse(data); // drawSnappedPolyline(); // }); } // function processSnapToRoadResponse(data) { // snappedCoordinates = []; // placeIdArray = []; // for (var i = 0; i < data.snappedPoints.length; i++) { // var latlng = new google.maps.LatLng( // data.snappedPoints[i].location.latitude, // data.snappedPoints[i].location.longitude); // snappedCoordinates.push(latlng); // placeIdArray.push(data.snappedPoints[i].placeId); // } // } // function drawSnappedPolyline() { // var snappedPolyline = new google.maps.Polyline({ // path: snappedCoordinates, // strokeColor: 'black', // strokeWeight: 3 // }); // snappedPolyline.setMap(map); // polylines.push(snappedPolyline); // }