I have implemented Google Maps JavaScript API v3 to contrive a custom store locator for my company's website. Let me start by saying that the code I have works for the two stores, but it would not be efficient or feasible if I added any more stores because of the "hacky" code used to make it work.
I am using the Google Maps Places Library to send "place details" requests to Google using the getDetails() method. On the callback, I am receiving the InfoWindow information (name, address, location) for each of my store locations.
I create a marker for each place, then use google.maps.event.addListener to coordinate the Place, Marker, and InfoWindow objects. This is where I encounter problems. The place details requests are not always received in the same order they are sent which throws off the indexing of my buttons that have a data-marker attribute set to 0 and 1, respectively, to correlate to the map markers.
Is there anyway to delay the second request until the first is finished? or write the script in a way that maintains ordinal integrity?
The first snippet of code below is my event handler to bind the click listener to each button using the .place.placeId property of the marker rather than the preferred technique of using the index of the markers array (the markers array holds the place details for the two stores).
None of the demos or examples in the Google Maps API documentation (Places Library) delineate the procedure for multiple places. Any tips, resources, or suggestions will be much appreciated
Website: http://m.alliancepointe.com/locate.html
Event Handler
$(".loc-btn").on('click', function () {
var me = $(this).data('marker');
var place1 = markers[0].place.placeId;
var myIndex = me == place1 ? 0 : 1;
google.maps.event.trigger(markers[myIndex], 'click');
});
Full JS
var markers = [];
var map;
var infowindow;
var service;
function initialize() {
var index;
var daddr;
var idVA = 'ChIJKezXgqmxt4kRXrAnqIwIutA';
var geoVA = '38.80407,-77.062881/Alliance+Pointe,+LLC';
var idDC = 'ChIJDQlqOLG3t4kRqDU3uNoy4hs';
var geoDC = '38.90188,-77.049161/Alliance+Pointe,+LLC';
var bounds = new google.maps.LatLngBounds();
var mapOptions = {
center: {lat: 38.90188, lng: -77.049161},
zoom: 10,
mapTypeControlOptions: {style: google.maps.MapTypeControlStyle.DROPDOWN_MENU}
};
map = new google.maps.Map(document.getElementById('map'),
mapOptions);
var request = [
{placeId: idVA, location: {lat: 38.80407, lng: -77.062881}},
{placeId: idDC, location: {lat: 38.90188, lng: -77.049161}}
];
var office = [
"Main Office",
"Principal Office"
];
infowindow = new google.maps.InfoWindow();
service = new google.maps.places.PlacesService(map);
for (var i = 0; i < request.length; i++) {
service.getDetails(request[i], function (placeResult, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
var id = placeResult.place_id;
var location = placeResult.geometry.location;
var trimAddr = placeResult.formatted_address.split(", ");
var image = {
url: 'images/icons/AP-marker_large.png',
scaledSize: new google.maps.Size(32, 54)
};
var marker = new google.maps.Marker({
map: map,
place: {
placeId: id,
location: location
},
icon: image,
title: "Get directions"
});
google.maps.event.addListener(marker, 'click', function () {
if (id == idVA) {
index = 0;
daddr = geoVA;
trimAddr[0] = "1940 Duke St #200";
} else {
index = 1;
daddr = geoDC;
trimAddr[0] = "2200 Pennsylvannia Ave NW";
}
infowindow.setContent('<div class="info-window title">' + placeResult.name + "</div><div class='info-window sub-title'>" + office[index] + '</div><div class="info-window">' + trimAddr[0] + '<br>' + trimAddr[1] + ", " + trimAddr[2] + '</div><div class="info-window direction-div"><div class="direction-icon"></div><a class="google-link save-button-link" target="_blank" href="https://www.google.com/maps/dir/Current+Location/' + daddr + '">Get Directions</a></div>');
infowindow.open(map, marker);
});
markers.push(marker);
//bounds.extend(location);
}
});
}
if (!bounds.isEmpty()) {
map.fitBounds(bounds);
}
$(".loc-btn").on('click', function () {
var me = $(this).data('marker');
var place1 = markers[0].place.placeId;
var myIndex = me == place1 ? 0 : 1;
google.maps.event.trigger(markers[myIndex], 'click');
//console.log("PlaceId = " + me);
//console.log("Adj index = " + myIndex);
//console.log("0:VA array index = " + markers[0].place.placeId);
//console.log("1:DC array index = " + markers[1].place.placeId);
});
google.maps.event.addListenerOnce(map, 'idle', function () {
$.mobile.loading("hide");
$(".loc-btn").prop("disabled",false);
});
}
google.maps.event.addDomListener(window, 'load', initialize);
HTML: Map & Buttons
<div data-role="content" class="full-width">
<figure id="map"></figure>
<div class="loc-btn-set">
<button disabled data-role="none" data-theme="a" data-marker="ChIJKezXgqmxt4kRXrAnqIwIutA" class="loc-btn nightly-button">VA <span>- Alexandria</span></button>
<button disabled data-role="none" data-theme="b" data-marker="ChIJDQlqOLG3t4kRqDU3uNoy4hs" class="loc-btn nightly-button">DC <span>- Washington</span></button>
</div>
</div>
The simpliest approach based on the given code would be to add the click-handler for the buttons inside the getDetails-callback.
Add this after the creation of the marker:
$('.loc-btn[data-marker="'+id+'"]').click(function(){
google.maps.event.trigger(marker,'click');
});
Related
I'm starting to learn Google Map. It's strange that when statically declared, markers are working and being displayed, but when they come from DB, they aren't being drawn on map.
// var markers = [[15.054419, 120.664785, 'Device1'], [15.048203, 120.692186, 'Device 2'], [15.033303, 120.694611, 'Device 3']];
var markers = [];
I have the entire code here, maybe I am missing something? I even used console log and I successfully pass all data from ajax to markers variable.
I think I got this code somewhere here in SO and modified it to fit in for my DB calls for records. I hope you can help me out on this one. Thank you!
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&callback=initialize"></script>
<script type="text/javascript">
var map;
var global_markers = [];
// var markers = [[15.054419, 120.664785, 'Device1'], [15.048203, 120.692186, 'Device 2'], [15.033303, 120.694611, 'Device 3']];
var markers = [];
var infowindow = new google.maps.InfoWindow({});
function initialize() {
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(15.058607, 120.660884);
var myOptions = {
zoom: 10,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
$.ajax({
type: 'GET',
url: 'control_panel/get_device_list_ajax',
success:
function (data) {
data = JSON.parse(data);
if (data['success']){
var device = data['device_list'];
device.forEach(function (dev) {
markers.push([dev['dev_geolat'], dev['dev_geolng'], dev['dev_name']]);
//console.log(markers);
});
addMarker();
} else {
}
}
});
}
function addMarker() {
console.log(markers);
for (var i = 0; i < markers.length; i++) {
// obtain the attribues of each marker
var lat = parseFloat(markers[i][0]);
var lng = parseFloat(markers[i][1]);
var trailhead_name = markers[i][2];
var myLatlng = new google.maps.LatLng(lat, lng);
var contentString = "<html><body><div><p><h2>" + trailhead_name + "</h2></p></div></body></html>";
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: "Coordinates: " + lat + " , " + lng + " | Trailhead name: " + trailhead_name
});
marker['infowindow'] = contentString;
global_markers[i] = marker;
google.maps.event.addListener(global_markers[i], 'click', function() {
infowindow.setContent(this['infowindow']);
infowindow.open(map, this);
});
}
}
window.onload = initialize;
</script>
EDIT
Here is the jsfiddle I used to work with this one http://jsfiddle.net/kjy112/ZLuTg/ (thank you to the one that lead me to this)
Could be related to the way you accessing to json rendered by ajax
markers.push([dev.dev_geolat, dev.dev_geolng, dev.dev_name]);
or the json content
I don't know how to close this question as I overlooked some problems on my DB but I'll be posting my answer if someone may come with the same problem (well, I am not sure about that hehe)
I get the same response from AJAX of the values in DB and I am not able to draw markers on MAP, I found that db->table->fields LAT LNG are referenced with a data type of DECIMAL (7,5) and changed it to FLOAT (10, 6) as to what is found in this GOOGLE MAP Tutorial - Using PHP/MySQL with Google Maps.
The issue at the field before was that higher values tend to be saved as 99.999999 instead of the actual value (e.g. 120.XXXXX) .
I am trying to render Google map with Latitude and Longitude from my MVC Model by using different examples. Google Map is displaying fine but it is not displaying the markers. I am very new to the Google Maps and feeling completely clueless about it. Can please anyone tell me how I can get the markers?
My MVC view is as follow
if (Model.WidgetType == "Map")
{
<div class="experienceRestrictedText">
<script src="//maps.google.com/maps/api/js?sensor=false&callback=initialize" type="text/javascript"></script>
<script type="text/javascript">
function initialize() {
var London = new google.maps.LatLng(#Html.Raw(Json.Encode(Model.UserLatitude)), #Html.Raw(Json.Encode(Model.UserLongitude)));
// These are options that set initial zoom level, where the map is centered globally to start, and the type of map to show
var mapOptions = {
zoom: 14,
center: London,
mapTypeId: google.maps.MapTypeId['ROADMAP']
};
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
$.get("/Home/GetMapLocations", function(data){
$.each(data, function(i, item){
var marker = new google.maps.Marker({
'position' : new google.maps.LatLng(item.Latitude, item.Longitude),
'map' : map,
'title': item.EngineerName
});
});
});
#*var data = #Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.lstMapLocations));
$.each(data, function (i, item){
var marker = new google.maps.Marker({
'position' : new google.maps.LatLng(item.Latitude, item.Longitude),
'map' : map,
'title': item.EngineerName
});
});*#
}
</script>
<div class="map" id="map" style="width:690px; height:400px;"></div>
</div>
}
MVC Controller is as follow
public ActionResult GetMapLocations()
{
var lstMapLocations = new List<MapLocation>();
var mapLocationModel1 = new MapLocation
{
EngineerName = "Engineer1",
SiteName = "Site1",
Latitude = 51.507351,
Longitude = -0.127758,
LstDouble = new List<double>()
};
var mapLocationModel2 = new MapLocation
{
EngineerName = "Engineer2",
SiteName = "Site2",
Latitude = 51.481728,
Longitude = -0.613576,
LstDouble = new List<double>()
};
var mapLocationModel3 = new MapLocation
{
EngineerName = "Engineer3",
SiteName = "Site3",
Latitude = 51.628611,
Longitude = -0.748229,
LstDouble = new List<double>()
};
var mapLocationModel4 = new MapLocation
{
EngineerName = "Engineer4",
SiteName = "Site4",
Latitude = 51.26654,
Longitude = -1.092396,
LstDouble = new List<double>()
};
lstMapLocations.Add(mapLocationModel1);
lstMapLocations.Add(mapLocationModel2);
lstMapLocations.Add(mapLocationModel3);
lstMapLocations.Add(mapLocationModel4);
foreach(var item in lstMapLocations)
{
item.LstDouble.Add(item.Latitude);
item.LstDouble.Add(item.Longitude);
item.LatLong = item.LstDouble.ToArray();
}
return Json(lstMapLocations);
}
I have found a work around to my problem and thought to share it for those who may stumble upon a similar issue. Courtesy stack overflow post particularly the answer posted by Atish Dipongkor. There may well be a better alternative to this problem but this approach has resolve my problem. I have made little change in that answer as Atish has used apostrophes while retrieving data from model which can break the functionality if any of the model field has string data with apostrophe in it. My appended solution with the above dummy data (in my question) is as follow
<div class="experienceRestrictedText">
<script src="//maps.google.com/maps/api/js?sensor=false&callback=initialize" type="text/javascript"></script>
<script type="text/javascript">
function initialize() {
var London = new google.maps.LatLng(#Html.Raw(Json.Encode(Model.UserLatitude)), #Html.Raw(Json.Encode(Model.UserLongitude)));
// These are options that set initial zoom level, where the map is centered globally to start, and the type of map to show
var mapOptions = {
zoom: 8,
center: London,
mapTypeId: google.maps.MapTypeId['ROADMAP']
};
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
#foreach (var item in Model.lstMapLocations)
{
<text>
var markerLatLong = new google.maps.LatLng(#(item.Latitude), #(item.Longitude));
var markerTitle = #Html.Raw(Json.Encode(item.EngineerName));
var markerContentString = #Html.Raw(Json.Encode(item.EngineerName)) + " At " + #Html.Raw(Json.Encode(item.SiteName));
var infowindow = new google.maps.InfoWindow({
content: markerContentString
});
var marker = new google.maps.Marker({
position: markerLatLong,
title: markerTitle,
map: map,
content: markerContentString
});
google.maps.event.addListener(marker, 'click', (function (marker) {
return function () {
infowindow.setContent(marker.content);
infowindow.open(map, marker);
}
})(marker));
</text>
}
}
</script>
<div class="map" id="map" style="width:690px; height:400px;"></div>
</div>
This script can be used as a standalone javascript or greasemonkey script. What I am trying to fix is the hover title and on-click's info-window (it should display the address). here is a jsFiddle
// ==UserScript==
// #name mapMarkers
// #namespace mapMarkers
// #include https://www.example.com/*
// #description map markers of addresses in table
// #version 1
// #grant none
// ==/UserScript==
// find the table and loop through each rows to get the 11th, 12th, 13th cell's content (street address, city and zip respectively
// convert to lat/lon and show markers on map
if (document.getElementById('main_report') !== null) {
API_js_callback = 'https://maps.googleapis.com/maps/api/js?v=3.exp&callback=initialize';
var script = document.createElement('script');
script.src = API_js_callback;
var head = document.getElementsByTagName("head")[0];
(head || document.body).appendChild(script);
var Table_1 = document.getElementById('main_report');
var DIVmap = document.createElement('div');
DIVmap.id = 'DIVmap';
DIVmap.style.border = '2px coral solid';
DIVmap.style.cursor = 'pointer';
DIVmap.style.display = '';
DIVmap.style.height = '35%';
DIVmap.style.margin = '1';
DIVmap.style.position = 'fixed';
DIVmap.style.padding = '1';
DIVmap.style.right = '1%';
DIVmap.style.bottom = '1%';
DIVmap.style.width = '35%';
DIVmap.style.zIndex = '99';
var DIVinternal = document.createElement('div');
DIVinternal.id = 'DIVinternal';
DIVinternal.style.height = '100%';
DIVinternal.style.width = '100%';
DIVinternal.style.zIndex = '999';
document.body.appendChild(DIVmap);
DIVmap.appendChild(DIVinternal);
//Adds a button which allows the user to re-run calcRoute
var reloadMapButton = document.createElement("button");
reloadMapButton.setAttribute("type", "button");
reloadMapButton.setAttribute("href", "#");
reloadMapButton.textContent="Reload map";
reloadMapButton.id="calcRoute";
reloadMapButton.style.zIndex = '1000';
document.getElementById('Content_Title').appendChild(reloadMapButton);
window.initialize = setTimeout(function () {
var myWindow;
try{
myWindow = unsafeWindow;
}catch(e){
myWindow = window;
}
google = myWindow.google;
directionsService = new google.maps.DirectionsService();
directionsDisplay = new google.maps.DirectionsRenderer();
var myLoc = new google.maps.LatLng(28.882193,-81.317936);
var myOptions = {
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: myLoc
}
map = new google.maps.Map(document.getElementById("DIVinternal"), myOptions);
var infoWindow1 = new google.maps.InfoWindow();
//var bounds = new google.maps.LatLngBounds();
var geocoder = new google.maps.Geocoder();
function codeAddress(address,i) {
setTimeout( function () { // timer to avoid google geocode limits
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
//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);
}
});
}, i * 350);
}
function calcRoute() {
if (Table_1.rows.length > 1) { // table has 1 empty row if no search results are returned and first row is always empty
var newPoint;
for (var i = 1, row; row = Table_1.rows[i]; i++) {
newPoint = codeAddress(row.cells[10].title + ', ' + row.cells[11].innerHTML + ', ' + row.cells[12].innerHTML, i);
// bounds.extend(newPoint);
marker = new google.maps.Marker({
position: newPoint,
map: map,
title: row.cells[10].title + ', ' + row.cells[11].innerHTML + ', ' + row.cells[12].innerHTML
});
google.maps.event.addListener(marker, 'click', function () {
infoWindow1.setContent(row.cells[10].title + ', ' + row.cells[11].innerHTML + ', ' + row.cells[12].innerHTML);
infoWindow1.open(map, this);
});
// Automatically center the map fitting all markers on the screen
// map.fitBounds(bounds);
}
}
}
//reloadMapButton.addEventListener('click', calcRoute);
document.getElementById("calcRoute").onclick = calcRoute;
calcRoute();
}, 1000);
} // if (document.getElementById('main_report') !== null)
sample data
Answer copied from the Reddit post:
If you carefully think through the code step by step, you can see why the infowindow isn't assigning itself to the markers. Starting from the calcRoute function:
if the table is more than one row
create newPoint variable
for each row in the table starting with the second one:
call the codeAddress function and assign it to newPoint
Let me cut in here. This is where your confusion is starting. codeAddress has no return statement (and even if it did, it would be asynchronous and wouldn't matter [AJAX]), so it isn't actually doing anything to newPoint. The whole marker is being created inside the codeAddress function, rendering the lines below this useless -- there is no position stored in newPoint so no marker is created, and thus no infoWindow is created.
Instead, you have to create the infoWindow inside the geocoding callback, right after you create the marker. You also have to assign that infoWindow to the marker using a click event. Also, if you want the hover title, just add it as a property of the marker called title.
The final code is here: http://pastebin.com/3rpWEnrp
You'll notice I cleaned it up a bit to make it more readable and clear:
The document's head can be accessed using document.head -- no need for getting it by the tag name
There is a shorthand for assigning two variables the same value: x = y = 3
No need for the z-index on the internal div; the external div already has it. (think of this like hold a piece of cardboard over something--anything on the cardboard is also lifted)
No need for the unsafeWindow; this is literally unsafe
Shorthand for definining multiple variables at once is var x = 3, y = 4;
You don't need the codeAddress function because you only call it once, so the whole contents of this just gets put into the calcRoute function.
It's less intrusive to use the console instead of alert, unless you really want the user to know, and in that case you need a simpler message
Why check if the table is longer than one row when the if statement won't fire in that case because it starts on row 2?
Change your calcRoute() function to call another function for each loop iteration. This will capture that function's parameters and local variables in a closure, so they will remain valid in the asynchronous event handler nested inside it.
You have a lengthy string expression repeated three times. Pull that out into a common variable so you only have to do it once.
Use var on your local variables. You're missing one on marker.
Be careful of your indentation. It is not consistent in your code: the marker click listener is not indented the same as the rest of the function it is nested inside. This makes it hard to see what is nested inside what.
Do not use this loop style:
for( var i = 1, row; row = Table_1.rows[i]; i++ ) { ... }
I used to advocate this type of loop, but it turned out to not be such a good idea. In an optimizing JavaScript environment, it is likely to force the array to become de-optimized. That may or may not happen in your particular code, and the array may be short enough that it just doesn't matter, but it's not a good habit these days. You're better off with a conventional loop with an i < xxx.length test.
So putting those tips together, we have this for your calcRoute():
function calcRoute() {
// table has 1 empty row if no search results are returned,
// and first row is always empty
if( Table_1.rows.length < 2 )
return;
for( var i = 1; i < Table_1.rows.length; i++ ) {
addMarker( i );
}
}
function addMarker( i ) {
var row = Table_1.rows[i];
var title =
row.cells[10].title + ', ' +
row.cells[11].innerHTML + ', ' +
row.cells[12].innerHTML;
var newPoint = codeAddress( title, i );
var marker = new google.maps.Marker({
position: newPoint,
map: map,
title: title
});
google.maps.event.addListener( marker, 'click', function () {
infoWindow1.setContent( title );
infoWindow1.open( map, this );
});
}
There are other problems here. You're calling this function:
var newPoint = codeAddress( ... );
But codeAddress() does not return a value! Nor could it return any useful value, because the function issues an asynchronous geocoder request. If you want to use the location provided by the geocoder, you will need to call a function from within the geocoder callback. I don't understand what you're trying to well enough to make a more specific suggestion here.
Thanks mostly to IanSan5653 on Reddit, I used mostly his code but had to change it a little. Here is working version on jsFiddle and the code below:
// ==UserScript==
// #name mapMarkers
// #namespace mapMarkers
// #include https://www.volusia.realforeclose.com/*
// #description map markers of addresses in table
// #version 1
// #grant none
// ==/UserScript==
// find the table and loop through each rows to get the 11th, 12th, 13th cell's content (street address, city and zip respectively
// convert to lat/lon and show markers on map
if (document.getElementById('main_report') != null) {
var script = document.createElement('script');
script.src = 'https://maps.googleapis.com/maps/api/js?v=3.exp&callback=initialize';
(document.head || document.body).appendChild(script);
var Table_1 = document.getElementById('main_report');
var DIVmap = document.createElement('div');
DIVmap.id = 'DIVmap';
DIVmap.style.border = '2px coral solid';
DIVmap.style.height = DIVmap.style.width = '35%';
DIVmap.style.margin = DIVmap.style.padding = '1';
DIVmap.style.position = 'fixed';
DIVmap.style.right = DIVmap.style.bottom = '1%';
DIVmap.style.zIndex = '999';
var DIVinternal = document.createElement('div');
DIVinternal.id = 'DIVinternal';
DIVinternal.style.height = DIVinternal.style.width = '100%';
document.body.appendChild(DIVmap);
DIVmap.appendChild(DIVinternal);
//Adds a button which allows the user to re-run calcRoute
var reloadMapButton = document.createElement("button");
reloadMapButton.setAttribute("type", "button");
reloadMapButton.textContent="Reload map";
reloadMapButton.id="calcRoute";
reloadMapButton.style.zIndex = '1000';
document.getElementById('Content_Title').appendChild(reloadMapButton);
// reloadMapButton.onclick = calcRoute;
window.initialize = function () {
var google = window.google,
directionsService = new google.maps.DirectionsService(),
directionsDisplay = new google.maps.DirectionsRenderer(),
myLoc = new google.maps.LatLng(28.882193,-81.317936),
myOptions = {
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: myLoc
},
infoWindow1 = new google.maps.InfoWindow(),
map = new google.maps.Map(document.getElementById("DIVinternal"), myOptions),
geocoder = new google.maps.Geocoder();
function calcRoute() {
for (var i = 1, row; row = Table_1.rows[i]; i++) {
console.log("processing row " + i);
address = row.cells[10].title + ', ' + row.cells[11].innerHTML + ', ' + row.cells[12].innerHTML,
setTimeout( function(addr) { // timer to avoid google geocode limits
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location,
title: addr
});
google.maps.event.addListener(marker, 'click', function() {
infoWindow1.setContent(addr);
infoWindow1.open(map,this);
});
} else {
console.error("Geocode was not successful for the following reason: " + status);
}
});
}(address), i * 400);
}
}
document.getElementById("calcRoute").onclick = calcRoute;
calcRoute();
}
}
So I am trying to make a simple application that will allow the user to search for restaurants and have the results show as markers on the map and as text below. The results object that returns from the textSearch doesn't provide detailed information like: phone number, pictures, etc. So i decided to create an array of place id's pushed from the results object, get the place details for each id, then push that into an array. The problem I get is a message from google saying I'm over my quota and I think it's because I'm requesting the place details for every single search result.
Is there a way I can request the place details only for the marker I click? Or is there a better solution to my problem? Thank you in advance for your help.
<!DOCTYPE html>
<html>
<head>
<title>gMap test</title>
<style type="text/css">
#map-canvas{
height:500px;
}
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places&sensor=false"></script>
<script type="text/javascript">
function performSearch(){
var locationBox;
var address = document.getElementById("address").value;
var searchRadius = metricConversion(document.getElementById("radius").value);
//gMaps method to find coordinates based on address
geocoder.geocode({'address':address}, function(results,status){
if(status == google.maps.GeocoderStatus.OK){
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map:map,
position: results[0].geometry.location
});
var latitude = results[0].geometry.location.A;
var longitude = results[0].geometry.location.F;
locationBox = new google.maps.LatLng(latitude, longitude);
}else{
errorStatus(status);
return;
}
//search request object
var request = {
query: document.getElementById('keyword').value,
location: locationBox,
radius: searchRadius,
//minPriceLvl: minimumPrice,
//maxPriceLvl: maximumPrice,
types: ["restaurant"]
}
//search method. sending request object and callback function
service.textSearch(request, handleSearchResults);
});
};
var latLngArray = [];
var placeIdArray = [];
//callback function
function handleSearchResults(results,status){
if( status == google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
placeIdArray.push(results[i].place_id)
latLngArray.push(results[i].geometry.location);
};
for(var j = 0; j<placeIdArray.length; j++){
service.getDetails({placeId: placeIdArray[j]},getDetails)
};
}
else{errorStatus(status)};
};
var detailedArray = [];
function getDetails(results,status){
if (status == google.maps.places.PlacesServiceStatus.OK) {
detailedArray.push(results);
for(var i = 0; i<detailedArray.length; i++){
createMarker(detailedArray[i],i);
}
}
else{
errorStatus(status)
};
}
//array of all marker objects
var allMarkers = [];
//creates markers and info windows for search results
function createMarker(place, i) {
var image = 'images/number_icons/number_'+(i+1)+'.png';
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location,
html:
"<div class = 'markerPop'>" + "<h3>" + (i+1) + ". " + place.name + "</h3><br>" + "<p>Address: "
+ place.formatted_address + "</p><br>" + "<p> Price Range: "+ priceLevel(place.price_level)
+ "</p>" + "</div>",
icon: image
});
allMarkers.push(marker);
marker.infowindow = new google.maps.InfoWindow();
//on marker click event do function
google.maps.event.addListener(marker, 'click', function() {
//service.getDetails({placeId: placeIdArray[j]},getDetails)
//sets infowindow content and opens infowindow
infowindow.setContent(this.html);
infowindow.open(map,this);
});
//create new bounds object
var bounds = new google.maps.LatLngBounds();
//iterates through all coordinates to extend bounds
for(var i = 0;i<latLngArray.length;i++){
bounds.extend(latLngArray[i]);
};
//recenters map around bounds
map.fitBounds(bounds);
};
var map;
var service;
var geocoder;
var infowindow;
function initialize(location){
var mapOptions = {
center: new google.maps.LatLng(37.804, -122.271),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
geocoder = new google.maps.Geocoder();
map = new google.maps.Map(document.getElementById("map-canvas"),mapOptions);
service = new google.maps.places.PlacesService(map)
infowindow = new google.maps.InfoWindow();
};
$(document).ready(function(){
initialize();
$('#search').on('click', function(){
removeMarkers();
performSearch();
});
});
//::::::Random Functions:::::::
//Clears all markers between searches
function removeMarkers(){
for(var i = 0; i<allMarkers.length;i++){
allMarkers[i].setMap(null);
};
};
//converts miles to meters for search object
function metricConversion(miles){
var meters;
meters = miles * 1609.34;
return meters;
}
//converts number value to $ sign
function priceLevel(number){
var moneySigns = ""
for(var i =0;i<=number;i++){
moneySigns += "$";
};
return moneySigns;
}
//errors for search results
function errorStatus(status){
switch(status){
case "ERROR": alert("There was a problem contacting Google Servers");
break;
case "INVALID_REQUEST": alert("This request was not valid");
break;
case "OVER_QUERY_LIMIT": alert("This webpage has gone over its request quota");
break;
case "NOT_FOUND": alert("This location could not be found in the database");
break;
case "REQUEST_DENIED": alert("The webpage is not allowed to use the PlacesService");
break;
case "UNKNOWN_ERROR": alert("The request could not be processed due to a server error. The request may succeed if you try again");
break;
case "ZERO_RESULTS": alert("No result was found for this request. Please try again");
break;
default: alert("There was an issue with your request. Please try again.")
};
};
</script>
</head>
<body>
<div id="map-canvas"></div>
<div id="searchBar">
<h3>search options</h3>
Location:<input type="text" id="address" value="enter address here" /><br>
Keyword<input type="text" id="keyword" value="name or keyword" /><br>
Advanced Filters:<br>
Search Radius:<select id="radius">
<option>5</option>
<option>10 </option>
<option>15 </option>
<option>20 </option>
<option>25 </option>
</select>miles<br>
<div id="minMaxPrice">
Min Price<select id="minPrice">
<option>$</option>
<option>$$</option>
<option>$$$</option>
<option>$$$$</option>
</select>
Max Price<select id="maxPrice">
<option>$</option>
<option>$$</option>
<option>$$$</option>
<option>$$$$</option>
</select>
</div>
<input type="button" id="search" value="Submit Search"/><br>
</div>
<div id='searchResults'>
</div>
</body>
</html>
The radarSearch example in the documentation requests the details of the marker on click.
code snippet:
var map;
var infoWindow;
var service;
function initialize() {
map = new google.maps.Map(document.getElementById('map-canvas'), {
center: new google.maps.LatLng(-33.8668283734, 151.2064891821),
zoom: 15,
styles: [{
stylers: [{
visibility: 'simplified'
}]
}, {
elementType: 'labels',
stylers: [{
visibility: 'off'
}]
}]
});
infoWindow = new google.maps.InfoWindow();
service = new google.maps.places.PlacesService(map);
google.maps.event.addListenerOnce(map, 'bounds_changed', performSearch);
}
function performSearch() {
var request = {
bounds: map.getBounds(),
keyword: 'best view'
};
service.radarSearch(request, callback);
}
function callback(results, status) {
if (status != google.maps.places.PlacesServiceStatus.OK) {
alert(status);
return;
}
for (var i = 0, result; result = results[i]; i++) {
createMarker(result);
}
}
function createMarker(place) {
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location,
icon: {
// Star
path: 'M 0,-24 6,-7 24,-7 10,4 15,21 0,11 -15,21 -10,4 -24,-7 -6,-7 z',
fillColor: '#ffff00',
fillOpacity: 1,
scale: 1 / 4,
strokeColor: '#bd8d2c',
strokeWeight: 1
}
});
google.maps.event.addListener(marker, 'click', function() {
service.getDetails(place, function(result, status) {
if (status != google.maps.places.PlacesServiceStatus.OK) {
alert(status);
return;
}
var htmlStr = "<b>"+result.name+"</b><br>";
if (result.website) htmlStr += "<a href='"+result.website+"'>"+result.website+"</a><br>";
if (result.adr_address) htmlStr += result.adr_address+"<br>";
infoWindow.setContent(htmlStr);
infoWindow.open(map, marker);
});
});
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map-canvas {
height: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&signed_in=true&libraries=places"></script>
<div id="map-canvas"></div>
I had the same issue some time ago. The geocoding function by google is done in order to avoid the user executing it on a large set of data (and then, avoid you to get a large amount of geocoded address easily).
My solution was to execute the geocoding function only when the user choose a particular place, and then, display this particular data (handled by the click on the pin).
I think it would be very useful to initiate a jsfiddle with a working version of your code.
Basically on your function :
google.maps.event.addListener(marker, 'click', function() {
//Execute geocoding function here on marker object
//Complete your html template content
infowindow.setContent(this.html);
infowindow.open(map,this);
});
I have a problem because i want to use this Json Result that returns Json List but my problem is how should i call the json result that i will be using to geocode and add marker to my Google Maps ? I used getJson and its not functioning but i dont tried yet the .ajax function
Here is my sets of codes:
<script type="text/javascript">
var geocoder;
var map;
function initialize() {
var minZoomLevel = 4;
var zooms = 7;
geocoder = new google.maps.Geocoder();
map = new google.maps.Map(document.getElementById('map'), {
zoom: minZoomLevel,
center: new google.maps.LatLng(38.50, -90.50),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
// Bounds for North America
var strictBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(15.70, -160.50),
new google.maps.LatLng(68.85, -55.90)
);
// Listen for the dragend event
google.maps.event.addListener(map, 'dragend', function () {
if (strictBounds.contains(map.getCenter())) return;
// We're out of bounds - Move the map back within the bounds
var c = map.getCenter(),
x = c.lng(),
y = c.lat(),
maxX = strictBounds.getNorthEast().lng(),
maxY = strictBounds.getNorthEast().lat(),
minX = strictBounds.getSouthWest().lng(),
minY = strictBounds.getSouthWest().lat();
if (x < minX) x = minX;
if (x > maxX) x = maxX;
if (y < minY) y = minY;
if (y > maxY) y = maxY;
map.setCenter(new google.maps.LatLng(y, x));
});
// Limit the zoom level
google.maps.event.addListener(map, 'zoom_changed', function () {
if (map.getZoom() < minZoomLevel) map.setZoom(minZoomLevel);
});
}
var iconBase = 'https://maps.google.com/mapfiles/kml/shapes/';
function codeAddress() {
var infowindow = new google.maps.InfoWindow();
$.getJson("Dashboard/DashboardIndex",null , function(address) {
$.each(address, function () {
var currVal = $(this).val();
address.each(function () {
geocoder.geocode({ 'address': currVal }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map: map,
icon: iconBase + 'man.png',
position: results[0].geometry.location,
title: currVal
})
google.maps.event.addListener(marker, 'click', (function (marker, i) {
return function () {
infowindow.setContent(currVal);
infowindow.open(map, marker);
}
})(marker, currVal));
address.push(marker);
}
else if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
setTimeout(codeAddress, 2000);
}
else {
alert("Geocode was not successful for the following reason: " + status);
}
});
});
});
});
return false;
}
window.onload = function () {
initialize();
codeAddress();
}
</script>
And my JsonResult at my Controller
public JsonResult LoadWorkerList()
{
var workerList = new List<Worker_Address>();
// check if search string has value
// retrieve list of workers filtered by search criteria
var list = (from a in db.Worker_Address
where a.LogicalDelete == false
select a).ToList();
List<WorkerAddressInfo> wlist = new List<WorkerAddressInfo>();
foreach (var row in list)
{
WorkerAddressInfo ci = new WorkerAddressInfo
{
ID = row.ID,
Worker_ID = row.WorkerID,
AddressLine1 = row.Address_Line1 + " " + row.Address_Line2+ " " +row.City + " "+ GetLookupDisplayValById(row.State_LookID),
LogicalDelete = row.LogicalDelete
};
wlist.Add(ci);
}
return Json(wlist.ToList().OrderBy(p => p.AddressLine1), JsonRequestBehavior.AllowGet);
}
Im thanking some who could help me in Advance :)
It's hard to guess where it goes wrong since you didn't post the JSON format and are getting errors (toLowerCase) of code you haven't posted. I think it's in the following area:
function codeAddress() {
var infowindow = new google.maps.InfoWindow();
$.getJson("Dashboard/DashboardIndex",null , function(address) {
console.log("full json object",address);//<--should show an array of objects
$.each(address, function () {
console.log(this);//<--here you can see what the JSON object is
var currVal = this["AddressLine1"];//<--guess from what your C# code looks like
//next each doesn't make much sense unless you have an array of arrays
// but the C# code makes json for a list (not a list of lists)
You can use IE for your console output but don't bother posting the output here because I can already tell you it's going to be [Object, object]. To get useful info you're going to have to use firefox with firebug or Chrome. To see the console you can press F12
The line:
setTimeout(codeAddress, 2000);
Could be optimized since now when you are making too many requests you'll fetch the entire address list again and start from the beginning instead of "waiting" for 2 seconds and continue where you were.
The following code:
map.setCenter(results[0].geometry.location);
Why set the center of the map within the loop? It'll just end up having the center of the last found address so you may as well do it outside the loop to set the center to last found address.