So, I found some instructions around and a few questions that seemed to answer this question, but none really worked for me or were very incomplete. I'm seeking a way to display the traditional google maps interaction of search and a pin is displayed on the map at the location. This marker, then, should be a blank option to include the data a user wants and the location saved to my database. I tried this sample by Google Dev and it worked for a custom click on the map, but the integration with a simple auto-complete search or even the google's own autocomplete search didn't quite worked.
I was wondering if there is a plugin or a technique (or a tutorial) that would suit this case (that I previously thought would be a simple matter as it is the traditional search on google maps). Thanks!
I can show you how I did this page http://www.a-zhotels.net/register, you could easily combine all the fields into one autocomplete address field. However, this should give you an idea.
First, create a function:
function getMapByGeoLocation() {
//build the address using many fields.
var postcode = $("#HotelPostcode").val();
var address = $("#HotelAddress").val();
var town = $("#HotelTown").val();
var city = $("#HotelCity").val();
var country = $("#HotelCountryId > option:selected").text();
var fulladdress = address + ', ' + town + ', ' + postcode + ', ' + city + ', ' + country;
geocoder.geocode(
{
'address': fulladdress
},
function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var location = results[0].geometry.location;
console.log(location);
//map and marker should be previously created
map.setCenter(location);
map.setZoom(14);
marker.setPosition(location);
//These 2 hidden inputs will be posted to the server
$("#HotelLatitude").val(location.Ya);
$("#HotelLongitude").val(location.Za);
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
This function is then called when the textbox and dropdowns change:
$("#HotelTown, #HotelAddress, #HotelPostcode").change(getMapByGeoLocation);
See below the function that creates the map:
var map;
var marker;
var geocoder;
function createMap() {
if (map) { //Map already exists
return;
}
if (!$('#mapCanvas').is(':visible')) {
return;
}
var mapCanvas = $("#mapCanvas")[0];
var averageLatitude = $("#HotelLatitude").val();
var averageLongitude = $("#HotelLongitude").val();
map = new google.maps.Map(mapCanvas, {
streetViewControl: true,
zoom: 13,
scrollwheel: false,
center: new google.maps.LatLng(averageLatitude, averageLongitude)
});
geocoder = new google.maps.Geocoder();
//Associate the styled map with the MapTypeId and set it to display.
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
marker = new google.maps.Marker({
position: new google.maps.LatLng(averageLatitude, averageLongitude),
draggable: true,
map: map
});
google.maps.event.addListener(marker, "dragend", function () {
var position = marker.getPosition();
map.panTo(position);
$("#HotelLatitude").val(position.lat());
$("#HotelLongitude").val(position.lng());
});
google.maps.event.addListener(map, "center_changed", function () {
var position = map.getCenter();
marker.setPosition(position);
$("#HotelLatitude").val(position.lat());
$("#HotelLongitude").val(position.lng());
});
}
createMap();
I am not sure what exactly you are looking for.
If you are looking for autocomplete field that adds a marker to the map after the user entered some string and opens an infowindow with a form on the map, is may be something like that: http://jsfiddle.net/XG9Qj/2/
It is important to notice, that this example only places a marker on the map if the user selected one of the suggestions from the autocomplete. To allow him to enter an arbitrary string you have to watch the input for RETURN and use the google maps geocoder on your own(1).
var geocoder = new google.maps.Geocoder();
geocoder.geocode(...)
Related
Is it possible to combine all polygon data (description & name) at a specific point into one InfoWindow when clicked? I have some overlapping polygons and the InfoWindow only displays the data from the topmost one. It seems this should be possible using Fusion Tables and a click listener on the map so that when someone clicks on the map, a query is sent to Fusion Tables to find all the Polygons that intersect with the point that was clicked (using ST_INTERSECTS with a CIRCLE and a very small radius). The only columns in my Fusion Table are Name, Description, and Geometry (containing standard KML ).
This is as far as I am with it. Polygons are displaying and circle is being rendered and centered onclick. InfoWindow is displaying [object Object].
var lat = 37.4;
var lng = -122.1;
var tableid = '1mxcz4IDL1U7ItrqulVzt01fMasj5zsmBFUuQh6iM';
var meters = 10000;
layer = new google.maps.FusionTablesLayer({
query: {
select: 'geometry',
from: tableid,
}
});
layer.setMap(map);
google.maps.event.addListener(layer, 'click', function(event) {
changeCenter(event);
});
function changeCenter(event) {
lat = event.latLng.lat();
lng = event.latLng.lng();
circle.setCenter(event.latLng);
}
circle = new google.maps.Circle({
center: new google.maps.LatLng(lat, lng),
radius: meters,
map: map,
fillOpacity: 0.2,
strokeOpacity: 0.5,
strokeWeight: 1,
});
comboname = new google.maps.FusionTablesLayer({
query: {
select: 'name',
from: tableid,
where: 'ST_INTERSECTS(geometry, CIRCLE(LATLNG(' + lat + ',' + lng + '),' + meters + '))'
}
});
google.maps.event.addListener(layer, 'click', function(e) {
// Display all of the names in the InfoWindow
e.infoWindowHtml = comboname;
});
}
A FusionTablesLayer doesn't provide any data related to the displayed features.
When you want to get data from the FusionTable you must request them via the REST-API (this also happens when the API will open an InfoWindow, when you take a look at the Network-Traffic you'll see that there is a request which loads the data for the InfoWindow).
The REST-API supports JSONP, so you may request the data directly via JS.
Requirements for SELECT
a valid google-API-key
the service Fusion Tables API must be enabled for the project
The FusionTable must be configured as downloadable (the table in your example already is downloadable)
Sample-implementation:
function initialize() {
var goo = google.maps,
//your google maps API-key
gooKey = 'someGoogleApiKey',
//FusionTable-ID
ftId = '1mxcz4IDL1U7ItrqulVzt01fMasj5zsmBFUuQh6iM',
//1km should be sufficient
meters = 1000,
map = new goo.Map(document.getElementById('map_canvas'),
{
zoom: 6,
center: new goo.LatLng(36.8,-111)
}),
//we use our own InfoWindow
win = new goo.InfoWindow;
//function to load ft-data via JSONP
ftQuery = function(query,callback){
//a random name for a global function
var fnc = 'ftCallback'+ new Date().getTime()
+ Math.round(Math.random()*10000),
url = 'https://www.googleapis.com/fusiontables/v2/query?',
params = {
sql : query,
callback : fnc,
key : gooKey
},
get =[],
script = document.querySelector('head')
.appendChild(document.createElement('script'));
for(var k in params){
get.push([encodeURIComponent(k),
encodeURIComponent(params[k])
].join('='));
}
window[fnc]=function(r){
callback(r);
delete window[fnc];
document.querySelector('head').removeChild(script);
}
script.setAttribute('src',url+get.join('&'));
},
ftLayer = new goo.FusionTablesLayer({
query: {
select: 'geometry',
from: ftId,
},
map:map,
suppressInfoWindows:true
});
goo.event.addListener(ftLayer,'click',function(e){
var sql ='SELECT name FROM ' + ftId +
' WHERE ST_INTERSECTS(geometry,'+
' CIRCLE(LATLNG(' +e.latLng.toUrlValue()+ '),'+ meters + '))',
cb = function(response){
if(response.error){
try{
alert(response.error.errors[0].message);
}
catch(e){
alert('error while retrieving data from fusion table');
}
return;
}
var content = [];
for(var r = 0; r < response.rows.length; ++r){
content.push(response.rows[r][0]);
}
//open the infowindow with the desired content
win.setOptions({
content:'<ol><li>'+content.join('</li><li>')+'</li></ol>',
map:map,
position:e.latLng
});
};
ftQuery(sql,cb);
});
}
google.maps.event.addDomListener(window, 'load', initialize);
Demo: http://jsfiddle.net/doktormolle/ckyk4oct/
please help me with this issue. I have the following code with working address variable. I tryed to add titles to the Infowindow so when a user clicks on a marker on the map to see some content in popup. Unfortunately, for all popups I can see the same title. I tested, it is a correct js array, but shows only the first titles that comes from the array.. Please help to solve this issue.. Thank you in advance guys !
<script type="text/javascript" charset="utf-8">
var map;
var address = < ? php echo json_encode($adr); ? > ;
var titles = < ? php echo json_encode($ttl); ? > ;
var x = 0;
var nbAddresses = address.length;
var geocoder;
var mark;
var contentString = titles[x];
function init() {
var moptions = {
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map"), moptions);
geocoder = new google.maps.Geocoder();
for (var i = 0; i < nbAddresses; i++) {
geocoder.geocode({
'address': address[i]
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
mark = new google.maps.Marker({
position: results[0].geometry.location,
map: map,
title: titles[x]
});
map.setCenter(results[0].geometry.location);
x++;
setInfoWindow();
}
});
}
function setInfoWindow() {
google.maps.event.addListener(mark, 'click', function(event) {
var iwindow = new google.maps.InfoWindow();
iwindow.setContent(contentString);
iwindow.open(map, this);
});
}
}
window.onload = init;
</script>
changing
x++;
setInfoWindow(); to
setInfoWindow();
x++;
sets the problem !
At the start of your program you set the contentString to the first element in the title array
var contentString = titles[x];
Then you use this variable inside the setInfoWindow function unchanged.
What if you changed the setInfoWindow to accept a contentString parameter like so
function setInfoWindow(contentString) {...
When you call setInfoWindow, pass in the title.
setInfoWindow(title[x]);
Make sure you increment x after you call this function, so move x++ below setInfoWindow call.
EDIT You will also notice a strange problem from time to time where some titles may appear on the wrong markers. This is because you are doing multiple geocodes at once, and you may get a response out of order.
The following modification would fix that.
for (var i = 0; i < nbAddresses; i++) {
geocoder.geocode({
'address': address[i]
}, return function(x) { // we define a function and call it straight away. The function returns another function which is our callback.
function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
mark = new google.maps.Marker({
position: results[0].geometry.location,
map: map,
title: titles[x]
});
map.setCenter(results[0].geometry.location);
setInfoWindow();
}
}
}(i)); // (i) after the function declaration calls the function and passes in the current value of i
}
So basically what we did here was define a function and run it straight away with the current value of 'i' passed in. The function would then return another function. This function will be run once the goecoding has finished. But now we have a reference to 'i' as it was when the function was defined. So you no longer need to keep a record of x outside this function as x will be equal to i which corresponds with the address passed into geocoder.
This is called a closure.
How do JavaScript closures work?
I am using Drupal 7 - Location, GMap module. I have a view that renders the result in a gmap. Everything works fine here and I get all the markers. Now I need a Find My location button which shows the users current location and adds a marker to the existing map.
Google Map Api V3 always works on a newly created map and I couldn't find a function which returns an existing map in the current page.
Gmap module provides a JS function - Drupal.gmap.getMap('ur-map-id') which is supposed to return a pointer to the map whose id is given. But this did not work.
Could someone please guide me as to how I should go about this? Can I get it work with Google Maps API? I need to retain the original map with all its markers.
Here's something for reference.
if (typeof(navigator.geolocation) !== 'undefined') {
var showUserOnMap = function(position) {
var map = Drupal.gmap.getMap('gmap-auto1map-gmap0');
if (typeof(map) !== 'undefined' && map !== false) {
latitude = position.coords.latitude;
longitude = position.coords.longitude;
var marker = {
latitude: latitude,
longitude: longitude,
markername: Drupal.t('You'),
opts: {
title: Drupal.t('You')
}
}
marker.opts.position = new google.maps.LatLng(latitude, longitude);
marker.opts.map = map.map;
Drupal.gmap.factory.marker(marker.opts);
}
};
// Get the current location
navigator.geolocation.getCurrentPosition(showUserOnMap);
}
I am having this issue as well, you can put this jquery code in for it to actually centre around your current location - but no marker is added. Just add it anywhere in your theme,
jQuery(document).ready(function() {
jQuery(function($) {
$.extend({
initialize: function () {
var m = Drupal.gmap.getMap('auto1map');
if (m.map && m.markersready) {
$.setCoords();
}
else {
m.bind('markersready', function(data) {
$.setCoords();
});
}
},
setCoords: function () {
navigator.geolocation.getCurrentPosition(function (position) {
var gmap = Drupal.gmap.getMap('auto1map').map;
var lat = position.coords.latitude;
var lng = position.coords.longitude;
gmap.setCenter(new google.maps.LatLng(lat, lng));
gmap.setZoom(13);
});
}
});
$.initialize();
});
});
Now you can centre your map around your location and now I need to figure out a way to place a marker down at this location.
I have a list of schools that I want to plot on a Google Map. I'm using Google's Geocoding Service to lookup the lng/lat for a given postcode, upon successfully retrieving this information I want to drop a marker, together with adding the appropriate event listener that opens an infobox when a given marker is clicked.
When I make a request to the geocoder it's in the context of a school, when I receive a callback I lose this context. You'll see from code below that I've come up with a clunky solution to this, although it fails occasionally when the geocoder results truncate the postcode.
Should I be using something like jQuery's Deferred Object to solve this issue?
var geocoder;
var map;
var infowindow
var iterator = 0;
geosearch = new Array();
function drop() {
for (var i = 0; i < schools.length; i++) {
setTimeout(function() { // delay added to prevent being throttled
addMarker();
iterator++;
}, i * 1000);
}
}
function addMarker() {
address = schools[iterator].addresses[0].address.zip;
geosearch[address] = schools[iterator]; // this is how I'm keeping track of initial request
geocoder.geocode( { 'address': address }, function(results, status) {
var school = geosearch[results[0].address_components[0].short_name]; // loading the school associated with the initial request, which only works if the postcode completely matches up - clunky!
if (status == google.maps.GeocoderStatus.OK) {
// each school has tags, I want to set a marker if certain tags exist
if ($.inArray('D', school.tags) > 0) {
var image = 'map_markers/brown_MarkerD.png';
} else if ($.inArray('C', school.tags) > 0) {
var image = 'map_markers/red_MarkerC.png';
} else if ($.inArray('B', school.tags) > 0) {
var image = 'map_markers/yellow_MarkerB.png';
} else if ($.inArray('A', school.tags) > 0) {
var image = 'map_markers/green_MarkerA.png';
} else {
var image = 'map_markers/blue_MarkerZ.png';
}
// add the marker to the map, using result
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location,
draggable: false,
icon: image,
shadow: 'http://www.google.com/mapfiles/arrowshadow.png',
animation: google.maps.Animation.DROP
});
// adds listening on marker so that popup box appears when clicked
google.maps.event.addListener(marker, 'click', (function(marker, school) {
return function() {
infowindow.setContent(
''+school.name+''
+'<address>'
+school.addresses[0].address.street+'<br />'
+school.addresses[0].address.city+'<br />'
+school.addresses[0].address.state+'<br />'
+school.addresses[0].address.zip+'<br />'
+school.addresses[0].address.country+'<br />'
+'</address>');
infowindow.open(map, marker);
}
})(marker, school));
} else {
console.log("* NOT found: " + status);
}
});
}
function initialise() {
geocoder = new google.maps.Geocoder();
infowindow = new google.maps.InfoWindow();
var latlng = new google.maps.LatLng(54.82659788452641,-3.417279296874991);
var mapOptions = {
zoom: 6,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
drop(); // loops through schools to add marker
}
I would suggest geocoding the addresses offline and storing the coordinates in your database (or wherever you are storing the addresses). Then use the coordinates to display the markers.
I would also suggest reviewing this article on geocoding strategies from the documentation
To answer your question, I would suggest using javascript function closures to associate the address with the callback function.
The problem I was experiencing here was just a questions of scope, and in particular the way that I was referencing the school within the addMarker() function. Rather than referencing the school within the schools array using the global iterator variable, I instead pass in this school, this way the correct school is always referenced on the callback that is created within this scope.
var geocoder;
var map;
var infowindow
var iterator = 0;
function drop() {
for (var i = 0; i < schools.length; i++) {
setTimeout(function() {
addMarker(schools[iterator]); // pass in the school as an argument
iterator++;
$('#current_school').text(iterator); // taken this out of addMarker()
}, i * 1000);
}
}
function addMarker(school) {
geocoder.geocode( { 'address': school.addresses[0].address.zip }, function(results, status) {
... // the inners from here remain the same
});
}
I have the following script to use the google maps API, I have to create a map that has more than one Marker (the balloon shaped icon pointing to something) and i need each of those markers to point on a different area of the map (i.e. different coordinates), how can i do it?
NOTE: I do not have latitude and longitude for the area on which marker has to be placed instead I have the address of the area on which marker has to be placed.
The code to display multiple markers on Google map is given below but it does not work as expected!
var map = null;
var geocoder = null;
function initializeNew() {
var allAddress = document.getElementById("HiddenField1").value;
var testary = new Array();
testary = allAddress.split("|");
if (GBrowserIsCompatible()) {
//calls map to appear inside <div> with id, "map_canvas"
map = new GMap2(document.getElementById("map_canvas"));
//adds zoom and arrow controls to map
//map.addControl(new GSmallMapControl());
var marker = null;
var i = 0;
for (i = 0; i < testary.length; i++) {
address = testary[i];
geocoder = new GClientGeocoder();
//converts a street address into geocode for the api
geocoder.getLatLng(
address,
function(point) {
if (!point) {
alert(address + " not found");
} else {
map.setCenter(point, 13);
marker = new GMarker(point);
map.addOverlay(marker);
map.setMapType(G_HYBRID_MAP);
//adds your own marker title and description in html
marker.openInfoWindowHtml("<p class='para1bold' style=\"font-weight: bold;\">Address</p><p class='para1'>" + address + "</p>");
//Add click event on push pin to open info window on click of the icon
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml("<p class='para1bold' style=\"font-weight: bold;\">Address</p><p class='para1'>" + address + "</p>");
});
//Provides map,satellite,hybrid and terrain views in the map along with zoom control
map.setUIToDefault();
}
}
)
}
}
}
I have stored address of group of items in an array and looped to display markers in the map. This displays only one marker for the last address present in the array. Please correct this code or provide new code to display multiple markers in Google map by providing address.
I ran into this exact same problem and fixed it. Look at the code that I have used. The specific bits are that marker needs to be an array and when you open the infowindow the content needs to be stored in the marker array. I would also suggest that you use something JSON instead which is easier to parse instead of separating with '|'.
try this: put var in front of marker
else {
map.setCenter(point, 13);
var marker = new GMarker(point);
map.addOverlay(marker);
map.setMapType(G_HYBRID_MAP);
//adds your own marker title and description in html
marker.openInfoWindowHtml("<p class='para1bold' style=\"font-weight: bold;\">Address</p><p class='para1'>" + address + "</p>");
//Add click event on push pin to open info window on click of the icon
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml("<p class='para1bold' style=\"font-weight: bold;\">Address</p><p class='para1'>" + address + "</p>");
});
UPDATE
var geocoder = new GClientGeocoder();
var addresses = ["new york","chicago"];
var curIndex = 0;
function showAddress() {
var _cur = addresses[curIndex];
geocoder.getLatLng(
_cur,
function(point) {
if (!point) {
alert(_cur + " not found");
} else {
console.log(_cur+":"+point);
}
//do next after done
curIndex++;
if(curIndex<addresses.length)
showAddress();
}
);
}
showAddress();
</script>