Refreshing google maps markers and infoBubbles using ajax - javascript

I am using asp mvc along with jquery and google maps api to display and update locations on a map.
My aim:
Use markers to point to a number of locations
Provide a small amount of information on those location using info bubbles info bubble repo
OnClick refresh markers and info bubbles
What I've achieved so far:
I am able to load the map, place the pointers and display the info bubbles. After a few hours of struggling I have also managed to refresh the markers when the ajax call is made.
My problem:
After the first update the markers refresh correctly but the info bubbles remain (I cannot work out how to clear them)
New bubbles are displayed along with the new markers BUT these bubbles do not hold any data
After the second update all markers disappear, but all info bubbles remain
Initial load
After call 1 (rent button clicked)
After call 2 (buy button clicked)
somePartialView.cshtml
#Html.HiddenFor(m => m.LatLng, new { #id = "latLng" })
<div id="map" class="google-maps">
<div id="map-canvas"></div>
</div>
Javascript
NB: While testing I am hard coding the lat and lng values in the viewModel so I know each time a call is made only four values will be returned, which Is why I have hard coded four string into the contentString array.
$(document).ready(function () {
var map;
var iterator = 0;
var markers = [];
var markerLatLng = [];
var contentString = [
'<div class="infobox-inner"><img src="assets/img/icon-1.png" alt=""/><span>Sarkkara Villa</span></div>',
'<div class="infobox-inner"><a href="08_Properties_Single.html"><img src="assets/img/icon-2.png" alt=""/><span>Sarkkara Flat</span></div>',
'<div class="infobox-inner"><a href="08_Properties_Single.html"><img src="assets/img/icon-3.png" alt=""/><span>Sarkkara Commercial</span></div>',
'<div class="infobox-inner"><img src="assets/img/icon-4.png" alt=""/><span>Sarkkara Appartment</span></div>'
];
var latlng = $("#latLng").val();
var aryOfLatLng = latlng.split(';');
loadMarkers(aryOfLatLng);
function loadMarkers(ary) {
$.each(ary, function (index, value) {
if (value !== "") {
var values = value.split(',')
var loc = new google.maps.LatLng(Number(values[0]), Number(values[1]));
markerLatLng.push(loc);
}
})
}
function initialize() {
map = new google.maps.Map(document.getElementById('map-canvas'), {
scrollwheel: false,
zoom: 12,
center: new google.maps.LatLng(52.520816, 13.410186) //Berlin
});
setTimeout(function () {
drop();
}, 1000);
}
// animate markers
function drop() {
for (var i = 0; i < markerLatLng.length; i++) {
setTimeout(function () {
addMarker();
}, i * 400);
}
}
function addMarker() {
var marker = new google.maps.Marker({
position: markerLatLng[iterator],
map: map,
icon: 'assets/img/marker.png',
draggable: false
//,animation: google.maps.Animation.DROP
});
markers.push(marker);
var infoBubble = new InfoBubble({
map: map,
content: contentString[iterator],
position: markerLatLng[iterator],
disableAutoPan: true,
hideCloseButton: true,
shadowStyle: 0,
padding: 0,
borderRadius: 3,
borderWidth: 1,
borderColor: '#74d2b2',
backgroundColor: '#ffffff',
backgroundClassName: 'infobox-bg',
minHeight: 35,
maxHeight: 230,
minWidth: 200,
maxWidth: 300,
arrowSize: 5,
arrowPosition: 50,
arrowStyle: 0
});
setTimeout(function () {
infoBubble.open(map, marker);
}, 200);
google.maps.event.addListener(marker, 'click', function () {
if (!infoBubble.isOpen()) {
infoBubble.open(map, marker);
}
else {
infoBubble.close(map, marker);
}
});
iterator++;
}
google.maps.event.addDomListener(window, 'load', initialize);
$("#rent").click(function () {
ajaxRequest("/Map/_IsForSale", false)
})
$("#buy").click(function () {
ajaxRequest("/Map/_IsForSale", true)
})
function ajaxRequest(targetUrl, data) {
$.ajax({
cache: false,
url: targetUrl,
type: "POST",
data: { 'isForSale': data },
success: function (data) {
successCallBack(data);
},
error: function (request, status, error) {
alert(error)
}
});
}
// Removes the markers from the map, but keeps them in the array. It will hide all markers.
function clearMarkers() {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(null);
}
}
function successCallBack(data) {
clearMarkers();
var latlng = data.substring(data.indexOf("value=") + 7, data.indexOf(";\""));
var ary = latlng.split(';');
$.each(ary, function (index, value) {
if (value !== "") {
var values = value.split(',')
var loc = new google.maps.LatLng(Number(values[0]), Number(values[1]));
markerLatLng.push(loc);
}
})
drop();
}
});

1. After the first update the markers refresh correctly but the info bubbles remain (I cannot work out how to clear them)
Just like how you created a markers array to store your created markers to later clear with your #clearMarkers. I'd do similar for the infoBubbles, e.g. #clearInfoBubbles. Make an infoBubbles array to store info bubbles. According to the source code (see line 968) in the info bubble repo, you can close an info bubble with InfoBubble#close. Call your #clearInfoBubbles where necessary. In your #successCallBack perhaps.
2. New bubbles are displayed along with the new markers BUT these bubbles do not hold any data
You are creating infoBubble here like this
var infoBubble = new InfoBubble({
map: map,
content: contentString[iterator],
...
});
with contentString, which is only hardcoded to be 4 elements long.
By the time #initialize is finished, iterator will be equal to 4. The subsequent call to #addMarker (when the 1st rent button is clicked) will try to create an info bubble with contentString[4], however, that is undefined. iterator is never reset to 0.
3. After the second update all markers disappear, but all info bubbles remain
All info bubbles remain because they're never closed.
I'm not sure what your "buy" request is giving back to you. I'd check to see that the response is returning the data that you're expecting. My guess is that no new markers are getting created at this point.

Related

Removing Google Maps Markers that are added dynamically with hover event over Chart.js Chart

I have a google map and a Chart.js chart. When you hover over a certain part of the chart a corresponding marker on the map is created. However I would like to remove the previous marker every time a new marker is place don the map but cannot seem to do so. I have tried pushing the markers to an array but when I try to log the array it only has an individual marker even if there are several on the map due to hovering. Here is the code I have in my map.js file (this comes after the mapinit function):
`function findLatLng(data, index) {
var getDataFiltered = formatData(data)
var markerPosition = {
lat: getDataFiltered[index].values.positionLat,
lng: getDataFiltered[index].values.positionLong }
var markers = []
var marker = new google.maps.Marker({position: markerPosition, map:
map, title: 'stamp'}); markers.push(marker)
addMarker(markerPosition) }
function addMarker(position) {
var markers = []
var marker = new google.maps.Marker({position: marker, map: map,
title: 'stamp'}); markers.push(marker)
if (marker.visible) {
marker.visible === false }
if (markers.length >= 2) {
markers[0].setMap(null); }
function clearMarkers(markers) {
if (markers.length > 1) {
markers[0].setMap(null);
} } }`
I call the findLatLang function from the graph.js file here with the hover event option.
` hover: {
onHover: function(element) {
if (element.length > 0) {
findLatLng(data, element[0]._index)
}
}
},`

Google Maps v3 markers not refreshing

So I have 3 Divs with hidden Lat Lng inputs, and some ajax pagination to change them out. On the initial load, I have a script that turns each one of the three pairs of Lat Lng inputs into a marker and pushes them into an array. All of this works good.
Now, when I update the 3 divs with my script file, and then try to use the provided v3 API method to clear and redraw the markers, I get the same spots on the map. And then, if I tell it to go back to page one results, it does delete the page 1 markers and I get the markers from page 2 on my map.
Here is the javascript:
var map;
var markers = [];
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(37.09024, -96.712891),
zoom: 3
};
map = new google.maps.Map(document.getElementById("map-canvas"),
mapOptions);
setRGBmarkers();
}
function setRGBmarkers() {
markers.push(new google.maps.Marker({
position: new google.maps.LatLng(
Number(document.getElementById("address-0-Lat").value),
Number(document.getElementById("address-0-Lng").value)
),
map: map
}));
//removed other markers for brevity
}
function setAllMap(map) {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(map);
}
}
function clearMarkers() {
setAllMap(null);
}
function deleteMarkers() {
clearMarkers();
markers = [];
}
var getPage = function () {
var $a = $(this);
var options = {
url: $a.attr("href"),
type: "get"
};
$.ajax(options).done(function (data) {
var target = $a.parents("div.pagedList").attr("data-nerd-target");
$(target).replaceWith(data);
});
deleteMarkers();
setRGBmarkers();
alert('done');
return false;
}
$(".body-content").on("click", ".pagedList a", getPage);
So it successfully goes out and gets the results. I'm guessing it somehow is running delete and set before its actually done replacing the markers so its setting the 'unreplaced data' again, hence why going back to page one results finally in page 2's markers showing up? Here's a snippet of what the div looks like if needed:
<div class="panel-body">
Event Description
<input id="address-0-Lat" type="hidden" value="34.0519079">
<input id="address-0-Lng" type="hidden" value="-118.24389300000001">
</div>
Well, Anto is correct, and upon investigating the jQuery documentation for the ajax() function, I see the correct place to put the code would be like so:
var getPage = function () {
var $a = $(this);
var options = {
url: $a.attr("href"),
type: "get"
};
$.ajax(options).done(function (data) {
var target = $a.parents("div.pagedList").attr("data-nerd-target");
$(target).replaceWith(data);
deleteMarkers();
setRGBmarkers();
alert('done');
});
return false;
}
$(".body-content").on("click", ".pagedList a", getPage);
Where the 'done' function is executed once the response comes back. Documenation and examples can be found here: http://api.jquery.com/jquery.ajax/

Google Maps API v.3 Clearing and adding markers on marker click

I am pulling markers from a MySQL database table of locations, which uses a nested set model for hierarchical categorization.
That part is working well.
I can place all markers on the map, using MarkerManager to show/hide at different zoom levels (using the 'depth' field from my table). That works nicely.
My issue is that if a marker for a country is clicked on, I would like all markers outside that country to be removed. Getting a single country's markers is trivial, I just feed a parent id to the xhr function. But clearing the markers... this is stumping me. I've been working at it for days, and just can't seem to make headway.
Here is the business-end of the JS
var map = new google.maps.Map(document.getElementById('gMap'), mapOptions);
// init the markerManager
var mgr = new MarkerManager(map);
//Associate the styled map with the MapTypeId and set it to display.
map.mapTypes.set('Dark', darkMap);
map.mapTypes.set('Light', lightMap);
map.setMapTypeId('Dark');
// lat lng bounds for center/zoom marker
var bounds = new google.maps.LatLngBounds();
// infowindow (infobox)
// init here, and re-use
var ib = new InfoBox();
var oldDraw = ib.draw;
ib.draw = function() {
oldDraw.apply(this);
jQuery(ib.div_).hide();
jQuery(ib.div_).fadeIn('slow');
}
// init marker list
// for removing 'old' markers and loading new ones
var markersArray= [];
// load markers from database
function loadMarkers(params) {
var params = params || {};
var pid = params.pid || 5;
deleteOverlays(pid,function(){
// alert("deleteOverlays(" + pid + ");")
$.getJSON('/map/xhr_get_descendants', {
pid : pid
}, function(data) {
var bounds = new google.maps.LatLngBounds();
$.each(data, function(key, val) {
if (val.lat_long && val.lat_long != '') {
var name = val.name;
var id = val.id;
var depth = val.depth;
var children = val.children;
var pos = val.lat_long.split(',');
var lat = parseFloat(pos[0]);
var long = parseFloat(pos[1]);
var myLatLng = new google.maps.LatLng(lat, long);
var html = "<b>NAME=>" + name + "\nID=>" + id + "\nDEPTH=>" + depth+"</b>";
var marker = new google.maps.Marker({
position : myLatLng
});
mgr.addMarker(marker, depth);
markersArray.push(marker);
var boxText = document.createElement("div");
google.maps.event.addListener(marker, 'mouseover', function() {
/*
getStats(id);
// */
boxText.innerHTML = html;
var infoBoxOptions = {
content : boxText,
disableAutoPan : true,
maxWidth : 0,
pixelOffset : new google.maps.Size(-140, 0),
zIndex : null,
boxClass : "infoBox",
closeBoxMargin : "2px 2px 2px 2px",
closeBoxURL : "http://www.google.com/intl/en_us/mapfiles/close.gif",
infoBoxClearance : new google.maps.Size(10, 10),
isHidden : false,
pane : "floatPane",
enableEventPropagation : false,
};
ib.setOptions(infoBoxOptions);
ib.open(map, marker);
})
google.maps.event.addListener(marker, 'mouseout', function() {
ib.close();
})
google.maps.event.addListener(marker, 'click', function() {
map.panTo(this.getPosition());
// getLinks(id);
if (children > 0) {
loadMarkers({
pid : id
});
}
})
bounds.extend(myLatLng);
}
});
map.fitBounds(bounds);
});
});
}
// clear markers
function deleteOverlays(pid,callback){
if((markersArray)&&(markersArray.length > 1)) {
for (var x in markersArray) {
markersArray[x].setMap(null);
markersArray[x]=null;
}
markersArray=[];
};
callback(pid);
}
function bindInfoWindow(marker, map, infoWindow, html) {
google.maps.event.addListener(marker, 'click', function() {
infoWindow.setContent(html);
infoWindow.open(map, marker);
});
}
loadMarkers({
pid:5
});
So quickly, you can see that I send a parent id to the loadMarkers() among other things if necessary, and do some stuff, and then I call the deleteMarkers() function, the callback of which creates the markers, adds them to the manager and to the main markersArray[]
for brevity I'm not going to add the full Ajax call to xhr_get_descendants/ because without the Model it would be a bit meaningless.
Anyway, the function returns id, name, depth of each "child" of the parent id provided, as well as how many children each one of those children might have.
I mean... this should work!!! LOL
I've been looking at it wayyyy too long. I'd seriously appreciate any suggestions, or hints, or even a "why the hell are you doing it this way?"
The markers displayed by the MarkerMangager are not the markers you create (and supply as argument to mgr.addMarker() ), the MarkerManager creates new Instances and these Instances will not be deleted when you delete the Markers stored in markersArray(what doesn't have any visual effect, because the markers stored in markersArray are not visible)
You may call mgr.clearMarkers() in deleteOverlays() to delete also the Instances created by the MarkerManager, but the complete approach with the markersArray is unnecessary. You don't need this array at all, simply call mgr.clearMarkers() to remove the visible Markers.

Google Map markers - add a custom icon with a unique label for each marker

I have implemented a google map with multiple markers but what i am failing to do is how to add a unique label for each marker i.e. Each marker needs have a letter:e.g.
Marker 1 needs to display 'A'
Marker 2 needs to display 'B'
Marker 3 needs to display 'C'
Marker 4 needs to display 'D'
...
an example of what i am trying to achieve is: http://www.athenos.com/locator/ --- enter 11205 in the zip search
here is a portion of my map code - my init and add_marker methods:
init : function() {
var self = this;
// set map property
var map = new google.maps.Map(self.dom_element, self.options);
self.map = map;
// set some other shit
new google.maps.Size(95, 77),
new google.maps.Point(0,0),
new google.maps.Point(47, 76);
// creating new bounds
var bounds = new google.maps.LatLngBounds();
// for loop to iterate through locations
for (var i = 0; i < self.locations.length; i++) {
// extend the bounds
bounds.extend(self.locations[i].latlng);
// add the marker
self.add_marker(self.locations[i].latlng, i);
}
// centers the map based on the existing map markers
self.map.fitBounds(bounds);
},
add_marker : function(latlng, marker_index) {
var self = this;
var marker = new google.maps.Marker({
position: latlng,
map: self.map,
icon: self.map_icon,
zIndex: 998,
id: marker_index // give the marker an ID e.g. 0, 1, 2, 3 - use this for indexing the listed venues
});
google.maps.event.addListener(marker, 'mouseover', function(event) {
var this_marker = this;
// executes handler and passes the marker as 'this' and event data as an argument
self.handle_marker_mouseover.call(self, this, event);
this_marker.setZIndex(999);
});
google.maps.event.addListener(marker, 'mouseout', function(event) {
// executes handler and passes the marker as 'this' and event data as an argument
self.handle_marker_mouseout.call(self, this, event);
});
google.maps.event.addListener(marker, 'click', function(event) {
// executes handler and passes the marker as 'this' and event data as an argument
self.handle_marker_click.call(self, this, event);
});
},
...
Please help.
Thanks in advance
just try to locate your icon, in marker's prop, at this url:
http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=7|00FF00|000000
So iterate with letters over the first part of the chld querystring parameter, and don't forget to choose your marker's color (latest two part, pipe separated)
Take a look at the article below. It's very simple. Use a marker with numeric labels or a marker with alphabet label (A,B..)
Multiple marker with labels in google map
for (i = 1; i <= markers.length; i++) {
var letter = String.fromCharCode("A".charCodeAt(0) + i - 1);
var data = markers[i - 1]
var myLatlng = new google.maps.LatLng(data.lat, data.lng);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: data.title,
icon: "http://maps.google.com/mapfiles/marker" + letter + ".png"
});
(function (marker, data) {
google.maps.event.addListener(marker, "click", function (e) {
infoWindow.setContent(data.description);
infoWindow.open(map, marker);
});
})(marker, data);
}
Go to this article for more details
Multiple marker with labels in google map

creating multiple infowindows in Bing Maps v7 and presenting data specific to pin

I'm currently trying to learn the Bing Maps API and currently trying to build a map with multiple pins that can be hovered to reveal a info window with that pins data. At the moment I'm experiencing a few problems. If anyone could help with the following points that would be great:
When I mouseleave a pin the info window doesn't get removed?
How can I use the data I retrieve in the addPin() to populate the
required info window?
In createInfoBox() I want to hide any active info window when the
map gets moved but this seems to get triggered even if the map isn't
moved?
If there are any improvements i can make please let me know
jsfiddle: http://jsfiddle.net/kyllle/vpepD/23/ and JS below
JS
var dealerMap = {
createInfoBox: function(infobox) {
var instance = this,
pushpin = infobox;
// Now create infowindows
var NewWindow = new Microsoft.Maps.Infobox(pushpin.getLocation(), {
title: 'title',
offset: new Microsoft.Maps.Point(-3, pushpin.getHeight() - 5),
zIndex: 999,
visible: true
});
//Display infowindow
instance.displayInfoBox(NewWindow, pushpin);
//Hide infowindow if map is moved - currently gets run without moving map
//Microsoft.Maps.Events.addHandler(dealerMap.myMap, 'viewchange', instance.hideInfoBox(NewWindow));
},
displayInfoBox: function(infobox, pin) {
var instance = this;
//Show updated infowindow
dealerMap.myMap.entities.push(infobox);
//Mouse out handler to remove window
Microsoft.Maps.Events.addHandler(pin, 'mouseleave', function() {
instance.hideInfoBox(NewWindow);
});
},
hideInfoBox: function(infobox) {
var instance = this;
console.log('this was called');
dealerMap.myMap.entities.remove(infobox);
},
addPin: function() {
var instance = this;
//make $.ajax json call
var response = data.dummy;
//on success make each pin with returned data
for (var i = 0, len = response.length; i < len; i++) {
var responseItem = response[i],
pinLocation = new Microsoft.Maps.Location(responseItem.lat, responseItem.long);
//Create new pin
var NewPin = new Microsoft.Maps.Pushpin(pinLocation, {
icon: 'http://www.kylehouston.com/testing/sportscar_' + responseItem.id +'.png',
width: 32,
height: 37
});
//Push new pin onto map
this.myMap.entities.push(NewPin);
//Event handlers to show and hide requested infowindow information
Microsoft.Maps.Events.addHandler(NewPin, 'mouseover', function(e) {
console.log(this);
dealerMap.createInfoBox(e.target);
});
}
},
init: function() {
var instance = this;
var mapOptions = {
credentials: "AvGoKWSuMorGQb5h4UyyatCBGmGzSZe7-dWQMzXt4qqz6mV_WCC5m-paxvQhednd",
center: new Microsoft.Maps.Location(37.09024, -95.712891),
zoom: 5,
enableClickableLogo: false,
enableSearchLogo: false
}
dealerMap.myMap = new Microsoft.Maps.Map(document.getElementById('mapDiv'), mapOptions);
//now add some pins
instance.addPin();
}
}
dealerMap.init();
});
I highly recommend only showing one infobox at a time on the map. Showing multiple infoboxes can crowd the map and make for a bad user experience. It also uses up a lot more resources. A better approach is to create a single infobox and reuse it for each pushpin as you want to display content. I wrote a blog post that shows how to do this here: http://rbrundritt.wordpress.com/2011/10/13/multiple-pushpins-and-infoboxes-in-bing-maps-v7/

Categories

Resources