How do I store google maps geocode info on client? - javascript

I want users to do the following:
1) Enter their Street Address and Zip Code and hit "Submit", which will trigger Google Maps to geocode the address and place a marker on the map. I'm using the below code for this (which is working fine and getting me all the address info I need):
var geocoder;
var map;
function initialize() {
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(37.7789, -122.3917);
var mapOptions = {
center: latlng,
zoom: 12,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
}
function codeAddress() {
var address = document.getElementById('streetAddress').value +", "+document.getElementById('zipCode').value;
geocoder.geocode( { 'address': address, 'region': 'US'}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[0].address_components) {
for (var i in results[0].address_components) {
if (typeof(results[0].address_components[i]) === "object" && results[0].address_components[i].types[0] == "street_number") {
var streetNumber= results[0].address_components[i].long_name;
} else if (typeof(results[0].address_components[i]) === "object" && results[0].address_components[i].types[0] == "route") {
var streetName= results[0].address_components[i].short_name;
} else if (typeof(results[0].address_components[i]) === "object" && results[0].address_components[i].types[0] == "neighborhood") {
var neighborhood= results[0].address_components[i].short_name;
} else if (typeof(results[0].address_components[i]) === "object" && results[0].address_components[i].types[0] == "administrative_area_level_1") {
var state= results[0].address_components[i].short_name;
} else if (typeof(results[0].address_components[i]) === "object" && results[0].address_components[i].types[0] == "postal_code") {
var zipCode= results[0].address_components[i].long_name;
}
}
}
console.log(streetNumber+", "+streetName+", "+neighborhood+", "+state+", "+zipCode);
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location
});
} else {
alert('Geocode was not successful for the following reason: ' + status);
}
});
}
google.maps.event.addDomListener(window, 'load', initialize);
2) After the user sees the marker, I want them to hit a "Confirm" button to submit this data to my server (I'm using Firebase via their Javascript API). The question I have is how do I best store the variables 'streetNumber', 'streetName', 'city', 'state', 'zipCode', and 'neighborhood' between the time that Google Maps returns the data and when the user hits "Confirm" button? The only thing I can think of is storing it on the browser window (e.g. window.streetName, window.streetNumber, etc), but I know that's not best practice.

You may e.g. store these data as properties of the button, it will be very easy to access them later(but it's also not a good practice).
The best thing you can do is to store all your objects in a single "class" (with all I mean everything that is global, currently also map, geocoder, codeAddress and initialize are global )
Here a sample code(ready to use, it doesn't expose any global property):
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false">
</script>
<script type="text/javascript">
//a self-executing, anonymous function
(function(opts,ns){
//"that" is our object, it holds all properties and methods
//and is only visible within the scope of this function
var that = {geocoder: null,
map: null,
opts: opts,
ns: ns,
postData: null},
goo = google.maps,
byId = function(id){return document.getElementById(id);};
//initialize the map
that.initialize=function() {
var latlng = new goo.LatLng(this.opts.lat,this.opts.lng);
var mapOptions = {
center: latlng,
zoom: 12,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
this.map = new goo.Map(byId(this.opts.ids.map), mapOptions);
//assign click-handlers to the buttons
goo.event.addDomListener(byId(this.opts.ids.btnGeo),'click',function(){
that.codeAddress.call(that);});
goo.event.addDomListener(byId(this.opts.ids.btnSend),'click',function(){
that.onSubmit.call(that);});
}
//send the data here
that.onSubmit=function(){
alert(JSON.stringify(that.postData));
}
//parse the address-components into an object
that.parseAddressComponents=function(ac){
var components={
street_number: ['streetNumber', 'long_name'],
route: ['streetName', 'short_name'],
administrative_area_level_1:['state', 'short_name'],
neighborhood: ['neighborhood', 'short_name'],
postal_code: ['zipCode', 'long_name']
},o={};
for(var i=0;i<ac.length;++i){
inner:for(var c in components){
if(ac[i].types[0]==c){
o[components[c][0]]=ac[i][components[c][1]];
break inner;
}
}
}
return o;
}
//geocoding-callback
that.geoCallback=function(results, status){
if (status == goo.GeocoderStatus.OK) {
//store the parsed address-components as property of "that"
that.postData=that.parseAddressComponents(results[0].address_components);
that.map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map: that.map,
position: results[0].geometry.location
});
} else {
that.postData={};
alert(status);
}
}
//geocoding
that.codeAddress=function() {
var address = [byId(this.opts.ids.uiAddr).value,
byId(this.opts.ids.uiZip).value].join(',');
//initialize geocoder on first run
if(!this.geocoder){this.geocoder=new goo.Geocoder();}
this.geocoder.geocode( { 'address': address, 'region': this.opts.region},
this.geoCallback);
}
//make "that" global when needed
if(ns)window[ns]=that;
//load-handler
goo.event.addDomListener(window, 'load',function(){
that.initialize();});
})
( //some properties for the object
{
lat:37.7789,
lng:-122.3917,
region:'US',
ids:{ map :'map_canvas',
btnGeo :'geobutton',
btnSend :'sendbutton',
uiAddr :'streetAddress',
uiZip :'zipCode'}
},
//supply a name for the object here when you want to make it global
null
);
/*]]>*/
</script>
<fieldset>
streetAddress:<input id="streetAddress" value="paisley park">
zipCode:<input id="zipCode" value="55422">
<input id="geobutton" type="button" value="geocode">
<input id="sendbutton" type="button" value="send">
</fieldset>
<div id="map_canvas" style="height:300px;"></div>

Related

Google map and places api exceeded your request quota for this API

i have create website on 000webhost. i use map on it and create new google api key but issue is that when i hit the api for first time through message exceeded your 'request quota for this API' how ever i never hit it before i hit the api for the first time with new api key. this is my php script.i need help
function initMap() {
var map = new google.maps.Map(document.getElementById('show_map'), {
center: {lat: 33.6518, lng: 73.1566},
zoom: 13
});
var input = document.getElementById('shopadd');
var options = {
types: ['(cities)'],
componentRestrictions: {country: 'pk'}
};
var autocomplete = new google.maps.places.Autocomplete(input,options);
// Bind the map's bounds (viewport) property to the autocomplete object,
// so that the autocomplete requests use the current map bounds for the
// bounds option in the request.
autocomplete.bindTo('bounds', map);
// Set the data fields to return when the user selects a place.
autocomplete.setFields(['address_components', 'geometry', 'name']);
autocomplete.setOptions({strictBounds: true});
var infowindow = new google.maps.InfoWindow();
var infowindowContent = document.getElementById('infowindow-content');
infowindow.setContent(infowindowContent);
var marker = new google.maps.Marker({
map: map,
anchorPoint: new google.maps.Point(0, -29)
});
autocomplete.addListener('place_changed', function() {
infowindow.close();
marker.setVisible(false);
var place = autocomplete.getPlace();
if (!place.geometry) {
// User entered the name of a Place that was not suggested and
// pressed the Enter key, or the Place Details request failed.
window.alert("No details available for input: '" + place.name + "'");
return;
}
var location = "Address " + place.formatted_address;
location += "Latitude " + place.geometry.location.lat();
location += "Longitude " + place.geometry.location.lng();
var lat = place.geometry.location.lat();
document.getElementById('lat').value = lat;
var lng = place.geometry.location.lng();
document.getElementById('lng').value = lng;
// If the place has a geometry, then present it on a map.
if (place.geometry.viewport) {
map.fitBounds(place.geometry.viewport);
} else {
map.setCenter(place.geometry.location);
map.setZoom(17); // Why 17? Because it looks good.
}
marker.setPosition(place.geometry.location);
marker.setVisible(true);
var add = '';
if (place.address_components.length>0) {
add = add.concat(
(place.address_components[0] && place.address_components[0].short_name || ''),' ',
(place.address_components[1] && place.address_components[1].short_name || ''),' ',
(place.address_components[2] && place.address_components[2].short_name || ''),' ');
}
document.getElementById('add').value = add;
infowindowContent.children['place-icon'].src = place.icon;
infowindowContent.children['place-name'].textContent = place.name;
infowindowContent.children['place-address'].textContent = add;
infowindow.open(map, marker);
});
// Sets a listener on a radio button to change the filter type on Places
// Autocomplete.
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key="my key"&libraries=places&callback=initMap" async defer></script>
Google changed their pricing model. The new plan gives you more flexibility and control over how you use our APIs. You can use as much or as little as you need and only pay for what you use each month.
As of July 16, 2018:
The Google Maps Platform APIs are billed by SKU.
Usage is tracked for each Product SKU, and an API may have more than one Product SKU.
Cost is calculated by: SKU Usage x Price per each use.
For each billing account, for qualifying Google Maps Platform SKUs, a $200 USD Google Maps Platform credit is available each month, and automatically applied to the qualifying SKUs.
For more information, visit this Link

google maps API getting lat and long values from DOM elements

I am working on a google maps API project.
I take lat and long values from a database and display them in HTML rendered by PHP.
I want to draw a route on map when I click the button with the lat&long values. ( check the image http://imgur.com/DkxlFbC )
But there is something going wrong and always taking the same values to draw the route.
I try to use changehandler but does not work.
index.php:
<?php
$test=mysql_query("SELECT lat, lng FROM markers ");
?>
<div class='container'>
<div class='row'>
<center>
<?php
while ($deneme=mysql_fetch_assoc($test)) {
extract($deneme);
echo '<br>';
echo '<h6 id="lat" class="box-design">'.$deneme['lat'].'</h6>';
echo '<h6 id="lng" class="box-design">'.$deneme['lng'].'</h6>';
echo '<br>';
echo '<input id="submit" onclick="myFunction()" type="submit" class="btn btn-primary" value="Button">';
echo '</div>';
}
?>
</center>
</div>
</div>
JS:
function myFunction() {
infoWindow = new google.maps.InfoWindow;
var directionsService = new google.maps.DirectionsService;
var directionsDisplay = new google.maps.DirectionsRenderer({ polylineOptions:{strokeColor:"#4a4a4a",strokeWeight:5}, suppressMarkers:true });
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
pos = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
infoWindow.setPosition(pos);
infoWindow.setContent('Location found.');
infoWindow.open(map);
map.setCenter(pos);
directionsDisplay.setMap(map);
destLatLng = new google.maps.LatLng(document.getElementById('lat').textContent, document.getElementById('lng').textContent);
directionsService.route({
origin: pos,
destination: destLatLng,
travelMode: 'DRIVING'
}, function(response, status) {
if (status === 'OK') {
directionsDisplay.setDirections(response);
} else {
window.alert('Directions request failed due to ' + status);
}
});
}, function() {
handleLocationError(true, infoWindow, map.getCenter());
});
} else {
handleLocationError(false, infoWindow, map.getCenter());
}
}
Like was mentioned in comments, the id attribute needs to be unique.
The id global attribute defines a unique identifier (ID) which must be unique in the whole document. 1
Use a technique like the one below to add a numeric index to each set of latitude and longitude values with associated buttons. Notice the last reference (i.e. onclick="myFunction('.$index++.')") uses the post-increment operator to increase the index for the next iteration of the while loop.
$index = 1;
while ($deneme=mysql_fetch_assoc($test)) {
extract($deneme);
echo '<br>';
echo '<h6 id="lat'.$index.'" class="box-design">'.$deneme['lat'].'</h6>';
echo '<h6 id="lng'.$index.'" class="box-design">'.$deneme['lng'].'</h6>';
echo '<br>';
echo '<input id="submit" onclick="myFunction('.$index++.')" type="submit" class="btn btn-primary" value="Button">';
echo '</div>';
}
Then since the javascript function myFunction() will now be passed an integer , that argument (e.g. named index) can be used to find the associated latitude and logitude values (or those could be used as arguments to in the function call instead).
So update the function definition to include that argument:
function myFunction() {
becomes:
function myFunction(index) {
and then this line:
destLatLng = new google.maps.LatLng(document.getElementById('lat').textContent, document.getElementById('lng').textContent);
can be updated to use that index:
destLatLng = new google.maps.LatLng(document.getElementById('lat' + index).textContent, document.getElementById('lng' + index).textContent);
Also, to re-use the same directions service and directions renderer, declare those at the start of the javascript, and then initialize them in the function that initializes the map (e.g. initMap()):
var map, pointA, directionsService, directionsDisplay;
function initMap() {
var options = {};
/*
code to setup options
*/
map = new google.maps.Map(document.getElementById('map-canvas'), options);
directionsService = new google.maps.DirectionsService;
directionsDisplay = new google.maps.DirectionsRenderer({ /* ... */});
}
That way the code in myFunction() can just directionsService.route() and directionsDisplay.setDirections() when appropriate.
Putting all of this together, we have something like demonstrated in this phpfiddle.
1https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id

JS variable "disappear" with no reason and gets empty

I am trying to get lat and long info from Google Geocoder, but although the information is properly extracted on the call that is being done, for some reason the js variable gets empty imediately after getting to my second alert on this piece of code (the one outside "if" condition):
var map, marker, latLong;
var geocoderlat = new google.maps.Geocoder();
var addresslat = '<?php echo str_replace(" ","+",$address);?>';
function initMap() {
geocoderlat.geocode( { 'address': addresslat}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
latLong = results[0].geometry.location;
alert("Inside IF: "+latLong);
} else {
latLong = '<?php echo $latitude.",".$longitude;?>';
}
})
alert("Outside: "+latLong);
var isDraggable = !('ontouchstart' in document.documentElement);
var mapOptions = {
center: new google.maps.LatLng(latLong),
zoom: 12,
(...)
Obviously there's a lot of code besides this part, but the rest of the code doesn't matter in this case because this variable is never again used anywhere in my code (I even searched with Agent Ransack all over the files so be sure that this variable was not being used anywhere else).
EDIT:
Ok, this is really, really weird...
function getGeoLatLong(addresslat) {
geocoderlat.geocode( { 'address': addresslat}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
return results[0].geometry.location;
} else {
return '<?php echo $latitude.",".$longitude;?>';
}
})
}
alert("Outside function: "+getGeoLatLong(addresslat));
This still returns "undefined" in the alert.
geocoderlat.geocode is taking more time to execute while the code execution has already reached your second alert. you need to use setTimeout to check the results or try this.
function initMap() {
geocoderlat.geocode( { 'address': addresslat}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
latLong = results[0].geometry.location;
alert("Inside IF: "+latLong);
alert("Outside: "+latLong);
var isDraggable = !('ontouchstart' in document.documentElement);
var mapOptions = {
center: new google.maps.LatLng(latLong),
zoom: 12,
(...)
} else {
latLong = '<?php echo $latitude.",".$longitude;?>';
}
})
Also, if you want to use latLong = '<?php echo $latitude.",".$longitude;?>'; as the default latLong you need to declare it at the top. then it will be anyways overridden when geocode finishes loading
EDIT
Try this.
function getGeoLatLong(addresslat) {
geocoderlat.geocode( { 'address': addresslat}, checkresults)
}
function checkresults(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
alert("Outside function: " + results[0].geometry.location);
//declare the big chunk of code as a function and make a call to it.
} else {
alert("Outside function: <?php echo $latitude.','.$longitude;?>");
//declare the big chunk of code as a function and make a call to it.
}
}
getGeoLatLong(addresslat);

maps only show gray with certain latt and long grabbed from database

I'm working with Googlemaps now. I use lattitude and longitude stored in the database. To call the data, I use simple ajax and it shows the latt and long as I wish.
However, It takes a long time to show the map based on the latt and long. Otherwise, It does not show anything. I don't know. How can I handle this?
Updated:
It looks there's a problem with the event.key onkeypress. I tried
clean code for that and it doesn't show anything !. ex: jsfiddle But That keyboard works on other code.
Here's the complete code:
JS/Ajax call the database through file inc.php:
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=places"></script>
<script>
function strQuery(str) {
if (str.length == 0) {
document.getElementById("valdata").value = "-33.8474, 151.2631";
return;
}
else{
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
document.getElementById("valdata").value = xmlhttp.responseText;
script_dkill()
}
}
xmlhttp.open("POST", "inc.php?q="+str, true);
xmlhttp.send(null);
}
}
//start: calling maps
var map;
var strlng;
function script_dkill() {
strlng = document.querySelector("#valdata").value;
if (strlng) {
var latlng = new google.maps.LatLng(strlng);
var myOptions = {
zoom: 12,
center: latlng,
panControl: true,
zoomControl: true,
scaleControl: true,
mapTypeId: google.maps.MapTypeId.SATELLITE
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
addMarker(new google.maps.LatLng(strlng), map);
}
}
function addMarker(latLng, map) {
var marker = new google.maps.Marker({
position: latLng,
map: map,
draggable: true,
animation: google.maps.Animation.DROP
});
return marker;
}
</script>
Here's the target(Output) in HTML:
<input id="qfront" name="qfront" placeholder="Ketik Nama Kampus ..." value="" type="text" onKeyPress="strQuery(this.value)"/>
<input id="valdata" name="valdata" type="text"/>
<div id="map_canvas" style="width:99.8%; height:280px; margin:0px; padding:0px;"></div>
and, here's the PDO the way I grab the data of latt and long (inc.php):
<?php
include('deep/cf/dbbs.php');
error_reporting(E_ALL);
?>
<?php
if(isset($_GET['q'])) {
$q = $_GET['q'];
}
$q = isset($_GET['q']) ? $_GET['q'] : '';
$nsUser="SELECT * FROM cliententry WHERE kampusterdekat=:q";
$uQuery = $mydb->prepare ($nsUser);
$uQuery->execute(array(':q' => $q));
$result = $uQuery->fetch(PDO::FETCH_ASSOC);
if ($result>0){
$googlemap=$result['googlemap'];
echo $googlemap;
}
else{
echo "<script>alert('Rent-house not registered yet');</script>";
}
?>
It's impossible to give you how the code running here. if you don't mind, please check here:
TEST-REAL-PAGE
Use keyword: "Universitas Lampung" since it's already inside the db.
I tends to focus on how the events work which I found it was wrong.
Data from db is interpreted as one value, ex: -2.9549663, 104.6929232
I must convert it into array first before called by JS in googlemap.
So, what makes it gray? It is because it didn't find the correct data format (like: -2.9549663, 104.6929232) in array. That's stupid of me.
Here's the way I convert which makes me stupid in a week:
var strlng = document.querySelector("#valdata").value;
var test1 = strlng.split(',');
var x = test1 [0];
var y = test1 [1];
After that, insert the x and y into the value of latt and long (latt and long is in array value), as follow:
var map;
function script_dkill() {
var strlng = document.querySelector("#valdata").value;
var test1 = strlng.split(',');
var x = test1 [0];
var y = test1 [1];
var latlng = new google.maps.LatLng(x,y);
var myOptions = {
zoom: 12,
center: latlng,
panControl: true,
zoomControl: true,
scaleControl: true,
mapTypeId: google.maps.MapTypeId.SATELLITE
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
addMarker(new google.maps.LatLng(x,y), map);
}
}
function addMarker(latLng, map) {
var marker = new google.maps.Marker({
position: latLng,
map: map,
draggable: true,
animation: google.maps.Animation.DROP
});
return marker;
everything finally goes so amazing! Done.
now I learn one more from JS.

Calculate driving distances Google Maps API

For a website where a user enters his address, I'm trying to find the location closest to him where the user can collect the ordered goods.
Based on the user's address I can narrow down the possible pick up locations to between 2 and 5. So I'd like to calculate the distance between user's address (point A) and the possible pick up locations.
The demo here works fine with just two addresses. I've adapted the code as much as I can to work with more than two addresses. I posted my JS code here since I can't seem to properly format it in SO.
In the code are two alerts. The first alert correctly shows the different pick up locations. But the second alert always shows the LAST pickup location.
Can anyone explain why?
HTML:
<p id="hello">Hello World</p>
JavaScript:
var geocoder, location1, location2, gDir;
function initialize(counter) {
if( counter == 0 ){
geocoder = new GClientGeocoder();
gDir = new GDirections();
}
GEvent.addListener(gDir, "load", function() {
var drivingDistanceMiles = gDir.getDistance().meters / 1609.344;
var drivingDistanceKilometers = gDir.getDistance().meters / 1000;
$("#results").append('<strong>Driving Distance: </strong>' + drivingDistanceKilometers + ' kilometers<br /><br />');
});
}
function getDistance(agency_add, counter) {
initialize(counter);
geocoder.getLocations(agency_add, function (response) {
if (!response || response.Status.code != 200) {
alert("Sorry, we were unable to geocode the address" + agency_add);
}
else {
location1 = {lat: response.Placemark[0].Point.coordinates[1], lon: response.Placemark[0].Point.coordinates[0], address: response.Placemark[0].address};
//alert("ONE: "+location1.address);
geocoder.getLocations(document.forms[0].address1.value, function (response) {
//alert("TWO: "+location1.address);
if (!response || response.Status.code != 200) {alert("Sorry, we were unable to geocode the second address");}
else {
location2 = {lat: response.Placemark[0].Point.coordinates[1], lon: response.Placemark[0].Point.coordinates[0], address: response.Placemark[0].address};
gDir.load('from: ' + location1.address + ' to: ' + location2.address);
}
});
}
});
}
$(document).ready(function(){
//put each agency address in an array
var agencies = [];
$(".agency_field").each(function(index) {
agencies.push($(this).val());
});
for (var i = 0; i < agencies.length; i++){
var res = getDistance(agencies[i], i);
}
});
you are calling geocoder.getLocations inside a loop. geocoder.getLocations runs asynchronously. when it receives the 2nd request while still processing the first, it cancels the first request.
If you want to multi-thread geocoder.getLocations you need to create multiple instances of it.

Categories