/** * @author Yaron Koren * @author Paladox */ /* global L */ function setupMapFormInput( inputDiv, mapService ) { /** * Round off a number to five decimal places - that's the most * we need for coordinates, one would think. */ function pfRoundOffDecimal( num ) { return Math.round( num * 100000 ) / 100000; } var map, marker, markers, mapCanvas, mapOptions; var numClicks = 0, timer = null; var coordsInput = inputDiv.find('.pfCoordsInput'); function googleMapsSetMarker( location ) { if ( marker === undefined ){ marker = new google.maps.Marker( { position: location, map: map, draggable: true } ); google.maps.event.addListener( marker, 'dragend', function( event ) { googleMapsSetMarker( event.latLng ); }); } else { marker.setPosition(location); } var stringVal = pfRoundOffDecimal( location.lat() ) + ', ' + pfRoundOffDecimal( location.lng() ); coordsInput.val( stringVal ) .attr( 'data-original-value', stringVal ) .removeClass( 'modifiedInput' ) .parent().find('.pfCoordsInputHelpers').remove(); } function leafletSetMarker( location ) { if ( marker === null) { marker = L.marker( location ).addTo( map ); } else { marker.setLatLng( location, { draggable: true } ); } marker.dragging.enable(); function setInput() { var stringVal = pfRoundOffDecimal( marker.getLatLng().lat ) + ', ' + pfRoundOffDecimal( marker.getLatLng().lng ); coordsInput.val( stringVal ) .attr( 'data-original-value', stringVal ) .removeClass( 'modifiedInput' ) .parent().find('.pfCoordsInputHelpers').remove(); } marker.off('dragend').on('dragend', function( event ) { setInput(); }); setInput(); } function openLayersSetMarker( location ) { // OpenLayers does not have a real marker move // option - instead, just delete the old marker // and add a new one. markers.clearMarkers(); marker = new OpenLayers.Marker( location ); markers.addMarker( marker ); // Transform the coordinates back, in order to display them. var realLonLat = location.clone(); realLonLat.transform( map.getProjectionObject(), // transform from Spherical Mercator Projection new OpenLayers.Projection("EPSG:4326") // to WGS 1984 ); var stringVal = pfRoundOffDecimal( realLonLat.lat ) + ', ' + pfRoundOffDecimal( realLonLat.lon ); coordsInput.val( stringVal ) .attr( 'data-original-value', stringVal ) .removeClass( 'modifiedInput' ) .parent().find('.pfCoordsInputHelpers').remove(); } if ( mapService === "Google Maps" ) { mapCanvas = inputDiv.find('.pfMapCanvas')[ 0 ]; mapOptions = { zoom: 1, center: new google.maps.LatLng( 0, 0 ) }; map = new google.maps.Map( mapCanvas, mapOptions ); var geocoder = new google.maps.Geocoder(); // Let a click set the marker, while keeping the default // behavior (zoom and center) for double clicks. // Code copied from http://stackoverflow.com/a/8417447 google.maps.event.addListener( map, 'click', function( event ) { timer = setTimeout( function(){ googleMapsSetMarker( event.latLng ); }, 200 ); }); google.maps.event.addListener( map, 'dblclick', function( event ) { clearTimeout( timer ); }); } else if (mapService === "Leaflet") { mapCanvas = inputDiv.find('.pfMapCanvas').get(0); mapOptions = { zoom: 1, center: [0, 0] }; var layerOptions = { attribution: '© OpenStreetMap contributors' }; map = L.map(mapCanvas, mapOptions); new L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', layerOptions).addTo(map); map.on( 'click', function( event ) { // Place/move the marker only on a single click, not a // double click (double clicks do a zoom). // Code based on https://stackoverflow.com/a/7845282 numClicks++; if (numClicks === 1) { timer = setTimeout( function() { leafletSetMarker( event.latlng ); numClicks = 0; }); } else { clearTimeout(timer); numClicks = 0; } }); } else { // if ( mapService == "OpenLayers" ) { var mapCanvasID = inputDiv.find( '.pfMapCanvas' ).attr( 'id' ); map = new OpenLayers.Map( mapCanvasID ); map.addLayer( new OpenLayers.Layer.OSM() ); map.zoomTo( 0 ); markers = new OpenLayers.Layer.Markers( "Markers" ); map.addLayer( markers ); map.events.register( "click", map, function( e ) { numClicks++; if (numClicks === 1) { timer = setTimeout( function() { var opx = map.getLayerPxFromViewPortPx(e.xy) ; var loc = map.getLonLatFromPixel( opx ); openLayersSetMarker( loc ); numClicks = 0; }); } else { clearTimeout(timer); numClicks = 0; } } ); } function toOpenLayersLonLat( map, lat, lon ) { return new OpenLayers.LonLat( lon, lat ).transform( new OpenLayers.Projection( "EPSG:4326" ), // transform from WGS 1984 map.getProjectionObject() // to Spherical Mercator Projection ); } function setMarkerFromCoordinates() { var coordsText = coordsInput.val(); var coordsParts = coordsText.split(","); if ( coordsParts.length !== 2 ) { coordsInput.val(''); return; } var lat = coordsParts[0].trim(); var lon = coordsParts[1].trim(); if ( !jQuery.isNumeric( lat ) || !jQuery.isNumeric( lon ) ) { coordsInput.val(''); return; } if ( lat < -90 || lat > 90 || lon < -180 || lon > 180 ) { coordsInput.val(''); return; } if ( mapService === "Google Maps" ) { var gmPoint = new google.maps.LatLng( lat, lon ); googleMapsSetMarker( gmPoint ); map.setCenter( gmPoint ); } else if ( mapService === "Leaflet" ){ var lPoint = L.latLng( lat, lon ); leafletSetMarker( lPoint ); map.setView( lPoint, 14 ); } else { // if ( mapService === "OpenLayers" ) { var olPoint = toOpenLayersLonLat( map, lat, lon ); openLayersSetMarker( olPoint ); map.setCenter( olPoint, 14 ); } } coordsInput.keypress( function( e ) { // Is this still necessary fro IE compatibility? var keycode = (e.keyCode ? e.keyCode : e.which); if ( keycode === 13 ) { setMarkerFromCoordinates(); // Prevent the form from getting submitted. e.preventDefault(); $(this).removeClass( 'modifiedInput' ) .parent().find('.pfCoordsInputHelpers').remove(); } }); coordsInput.keydown( function( e ) { if ( ! coordsInput.hasClass( 'modifiedInput' ) ) { coordsInput.addClass( 'modifiedInput' ); var checkMark = $('').addClass( 'pfCoordsCheckMark' ).css( 'color', 'green' ).html( '✔' ); var xMark = $('').addClass( 'pfCoordsX' ).css( 'color', 'red' ).html( '✘' ); var marksDiv = $('').addClass( 'pfCoordsInputHelpers' ) .append( checkMark ).append( ' ' ).append( xMark ); coordsInput.parent().append( marksDiv ); checkMark.click( function() { setMarkerFromCoordinates(); coordsInput.removeClass( 'modifiedInput' ); marksDiv.remove(); }); xMark.click( function() { coordsInput.removeClass( 'modifiedInput' ) .val( coordsInput.attr('data-original-value') ); marksDiv.remove(); }); } }); function setMarkerFromAddress() { var addressText = inputDiv.find('.pfAddressInput').val(), alert; if ( mapService === "Google Maps" ) { geocoder.geocode( { 'address': addressText }, function(results, status) { if (status === google.maps.GeocoderStatus.OK) { map.setCenter(results[0].geometry.location); googleMapsSetMarker( results[0].geometry.location ); map.setZoom(14); } else { alert("Geocode was not successful for the following reason: " + status); } }); //} else { // Leaflet, OpenLayers // Do nothing, for now - address lookup/geocode is // not yet enabled for Leaflet or OpenLayers. } } inputDiv.find('.pfAddressInput').keypress( function( e ) { // Is this still necessary fro IE compatibility? var keycode = (e.keyCode ? e.keyCode : e.which); if ( keycode === 13 ) { setMarkerFromAddress(); // Prevent the form from getting submitted. e.preventDefault(); } } ); inputDiv.find('.pfLookUpAddress').click( function() { setMarkerFromAddress(); }); if ( coordsInput.val() !== '' ) { setMarkerFromCoordinates(); map.setZoom(14); } } jQuery(document).ready( function() { jQuery(".pfGoogleMapsInput").each( function() { setupMapFormInput( jQuery(this), "Google Maps" ); }); jQuery(".pfLeafletInput").each( function() { setupMapFormInput( jQuery(this), "Leaflet" ); }); jQuery(".pfOpenLayersInput").each( function() { setupMapFormInput( jQuery(this), "OpenLayers" ); }); });