Following up on this problem, this seems to happen only in Windows, and also some calculations I am doing with latitudes / longitudes are also returning NAN! Seems to be a php on windows problem.
Following up on this problem, this seems to happen only in Windows, and also some calculations I am doing with latitudes / longitudes are also returning NAN! Seems to be a php on windows problem.
OK, I finally figured this out and I’m sharing this in hopes that it will help someone else. I wanted to dynamically add and remove markers every time the map bounds were changed. In my original php script I added a listener event:
$ce = new EGMapEvent('bounds_changed', 'makeAjaxRequest();', true, EGMapEvent::TYPE_EVENT_DEFAULT);
$gMap->addEvent($ce);
Also, I make a call to makeAjaxRequest() on map initialization (per Antonio’s advice):
$gMap->renderMap(array('makeAjaxRequest();'));
The biggest problem I had was with the makeAjaxRequest function (since I’ve never coded in JS before and am totally new to the maps API). I wanted to use an AJAX call to get the listings for a particular area, but I wanted to remove any other items on the map that were out of bounds. I tried the clearMarkers() method for the clusterer, but that would remove all the markers everytime I dragged or changed zoom levels. The map would blink and also the infowindows wouldn’t work correctly. So here’s my solution:
var cluster = null;
var listenerHandle = null;
var markers = new Array();
function makeAjaxRequest(){
var center = EGMap0.getCenter();
var bounds = EGMap0.getBounds();
var southWest = bounds.getSouthWest();
var northEast = bounds.getNorthEast();
var swLat = southWest.lat();
var swLng = southWest.lng();
var neLat = northEast.lat();
var neLng = northEast.lng();
var message = "";
// Create a cluster if it doesn't exist already
if(!cluster){
cluster = new MarkerClusterer(EGMap0, {}, {maxZoom:15, styles: [{'width':'53','height':'52','url':'http://localhost/m1.png','textColor':'#ffffff'},{'width':'56','height':'55','url':'http://localhost/m2.png','textColor':'#000000'},{'width':'66','height':'65','url':'http://localhost/m3.png','textColor':'white'},{'width':'78','height':'77','url':'http://localhost/m4.png','textColor':'white'},{'width':'90','height':'89','url':'http://localhost/m5.png','textColor':'white'}]});
}
// Now check to see if all the markers in the array are still withing bounds
// Remove any markers that are not in bounds
if(markers){
for (var j=0; j < markers.length; j++){
var marker = markers[j];
var markerPosition = marker.getPosition();
var markerLat = markerPosition.lat();
var markerLng = markerPosition.lng();
if ((swLat < markerLat && markerLat < neLat) && (swLng < markerLng && markerLng < neLng)){
//Do nothing. marker is within bounds
}else{
// Marker is out of bounds. Remove it from the array and the cluster.
markers.splice(j, 1);
var success = cluster.removeMarker(marker);
}
}
}
jQuery.post('index.php?r=site/getListings', {swLat: swLat, swLng: swLng, neLat: neLat, neLng: neLng}, function(data){
var i = 1;
var infowindow;
jQuery(data).find("marker").each(function(){
var item = jQuery(this);
var id = parseInt(item.attr("id"));
var markerLat = parseFloat(item.attr("lat"));
var markerLng = parseFloat(item.attr("lng"));
var latlng = new google.maps.LatLng(parseFloat(item.attr("lat")),
parseFloat(item.attr("lng")));
var title = item.attr("title");
var info = item.attr("info");
var type = item.attr("type");
var markerExists = false;
if (markers){
// markers array exists...
for (var j=0; j < markers.length; j++){
var zIndex = markers[j].getZIndex();
if (zIndex == id){
markerExists = true;
break;
}
}
if(!markerExists){
// We give each marker a unique z-index. It's the only damn way to keep track of a unique marker
if ((swLat < markerLat && markerLat < neLat) && (swLng < markerLng && markerLng < neLng)){
var marker = new google.maps.Marker({ position: latlng,
title: title,
zIndex: id,
icon: new google.maps.MarkerImage("http://localhost/snl/library.png", new google.maps.Size(32,37), new google.maps.Point(0,0), new google.maps.Point(16,16.5))
});
(function(i, marker) {
listenerHandle = google.maps.event.addListener(marker, 'click', function() {
if(!infowindow){
infowindow = new google.maps.InfoWindow();
}
infowindow.setContent(info);
infowindow.open(EGMap0, marker);
});
})(i, marker);
// Add the marker to the markers array
markers.push(marker)
// Add the marker to the cluster
cluster.addMarker(marker);
}
}
}else{
if ((swLat < markerLat && markerLat < neLat) && (swLng < markerLng && markerLng < neLng)){
var marker = new google.maps.Marker({ position: latlng,
title: title,
zIndex: id,
icon: new google.maps.MarkerImage("http://localhost/snl/library.png", new google.maps.Size(32,37), new google.maps.Point(0,0), new google.maps.Point(16,16.5))
});
(function(i, marker) {
listenerHandle = google.maps.event.addListener(marker, 'click', function() {
if(!infowindow){
infowindow = new google.maps.InfoWindow();
}
infowindow.setContent(info);
infowindow.open(EGMap0, marker);
});
})(i, marker);
// Add the marker to the markers array
markers.push(marker)
// Add the marker to the cluster
cluster.addMarker(marker);
}
}
i++;
}); // End .each
});
}
For my case, every listing has a unique id. I assign this id to the zIndex of each marker. I’m using it pretty much like a handle to the marker. That way, I don’t redundantly add any markers to the cluster or the markers array. Seems to work pretty well. If anyone has a better way or any suggestions, I would love them! Thanks again Antonio for this great extension and for pointing me in the right direction.
Sorry, found some issues with last version of makeAjaxRequest (Mainly with infoWindows). Here’s the fixed version:
var cluster = null;
var markers = new Array();
var infowindow;
function makeAjaxRequest(){
var center = EGMap0.getCenter();
var bounds = EGMap0.getBounds();
var southWest = bounds.getSouthWest();
var northEast = bounds.getNorthEast();
var swLat = southWest.lat();
var swLng = southWest.lng();
var neLat = northEast.lat();
var neLng = northEast.lng();
var message = "";
// Create a cluster if it doesn't exist already
if(!cluster){
cluster = new MarkerClusterer(EGMap0, {}, {maxZoom:15, styles: [{'width':'53','height':'52','url':'http://localhost/m1.png','textColor':'#ffffff'},{'width':'56','height':'55','url':'http://localhost/m2.png','textColor':'#000000'},{'width':'66','height':'65','url':'http://localhost/m3.png','textColor':'white'},{'width':'78','height':'77','url':'http://localhost/m4.png','textColor':'white'},{'width':'90','height':'89','url':'http://localhost/m5.png','textColor':'white'}]});
}
// Now check to see if all the markers in the array are still within bounds
// Remove any markers that are not in bounds
if(markers){
for (var j=0; j < markers.length; j++){
var marker = markers[j];
var markerPosition = marker.getPosition();
var markerLat = markerPosition.lat();
var markerLng = markerPosition.lng();
if ((swLat < markerLat && markerLat < neLat) && (swLng < markerLng && markerLng < neLng)){
//Do nothing. marker is within bounds
}else{
// Marker is out of bounds. Remove it from the array and the cluster.
markers.splice(j, 1);
var success = cluster.removeMarker(marker);
}
}
}
jQuery.post('index.php?r=site/getListings', {swLat: swLat, swLng: swLng, neLat: neLat, neLng: neLng}, function(data){
jQuery(data).find("marker").each(function(){
var item = jQuery(this);
var id = parseInt(item.attr("id"));
var markerLat = parseFloat(item.attr("lat"));
var markerLng = parseFloat(item.attr("lng"));
var latlng = new google.maps.LatLng(parseFloat(item.attr("lat")),
parseFloat(item.attr("lng")));
var title = item.attr("title");
var info = item.attr("info");
var type = item.attr("type");
var markerAdded = false;
var markerExists = false;
var marker = new google.maps.Marker({ position: latlng,
title: title,
zIndex: id,
icon: new google.maps.MarkerImage("http://localhost/snl/library.png", new google.maps.Size(32,37), new google.maps.Point(0,0), new google.maps.Point(16,16.5))
});
if (markers){
// markers array exists...
for (var j=0; j < markers.length; j++){
var zIndex = markers[j].getZIndex();
if (zIndex == id){
markerExists = true;
break;
}
}
if(!markerExists){
// We give each marker a unique z-index. It's the only damn way to keep track of a unique marker
if ((swLat < markerLat && markerLat < neLat) && (swLng < markerLng && markerLng < neLng)){
markerAdded = true;
// Add the marker to the markers array
markers.push(marker)
// Add the marker to the cluster
cluster.addMarker(marker);
}
}
}else{
if ((swLat < markerLat && markerLat < neLat) && (swLng < markerLng && markerLng < neLng)){
markerAdded = true;
// Add the marker to the markers array
markers.push(marker)
// Add the marker to the cluster
cluster.addMarker(marker);
}
}
if(markerAdded){
(function(marker) {
google.maps.event.addListener(marker, 'click', function() {
if(!infowindow){
infowindow = new google.maps.InfoWindow();
}
infowindow.setContent(info);
infowindow.open(EGMap0, marker);
});
})(marker);
}
}); // End .each
});
}
Hi Nerela, Please review the code posted by TwinMoon on this thread (Thanks for sharing) as you will be able to find your answer (is exactly the same but varying the way the ajax call is performed (instead of a map event, use a js click function)
PS: Suerte en tu carrera
Then is another story… I am working on a Mac… it will make the find of this error a bit hard.
Nevertheless, a division returning a NaN? mmmm… have you check the float format of your machine? do you pass the lat and lon as numeric strings or float?
Thanks Antonio and thanks TwinMoons for sharing it but I was trying your code and I found some issues… It didn’t work for me… Firebug shows 2 errors: bounds is undefined (it doesn’t take .getBounds as a EGMap0 function) and the most important error, at least in my case, is “MarkerClusterer is not defined”… I also tried to define it in other ways as new google.maps.MarkerClusterer() and in this case says me that MarkerClusterer() isn’t a constructor… Why is happening this? Any suggestion?
And Antonio maybe is a basic thing but I am a newbie… why you can access your map in the variable EGMap0? Could you also access other php/egmaps variables as for example an $m=new EGMapMarker() and in what way??
Thanks,
that variable is created automatically when you use the EGMap extension, and for the MarkerClusterer you require to activate the plugin.
I get the same “bounds is undefined” error from FireBug, but when I check the values for the boundaries, they are all correct, so I’m not sure what the deal is with FireBug. As for the markerclusterer issue, since I’m not using the EGMap class to load the clusterer and setting it up via javascript directly, you need to manually register the javascript file using Yii::app()->getClientScript()->registerScriptFile();
OK, this problems with the bounds being undefined is becoming a bit of a big problem. For some reason, the map isn’t initialized when I first call the makeAjaxRequest call. This:
var bounds = EGMap0.getBounds();
returns undefined at first. I have checked and the jQuery(window).load() function is setup correctly, but for some reason the bounds are undefined at first:
jQuery(window).load(function() {
function EGMapContainer1_init(){
var mapOptions = {center:new google.maps.LatLng(33.877243, -117.962628),
zoom:13,
mapTypeId:google.maps.MapTypeId.ROADMAP,
mapTypeControlOptions:{position:google.maps.ControlPosition.RIGHT_TOP,
style:google.maps.MapTypeControlStyle.DROPDOWN_MENU}};
EGMap0 = new google.maps.Map(document.getElementById("EGMapContainer1"), mapOptions);
google.maps.event.addListener(EGMap0, "bounds_changed", function() {getListings();});
getListings();
}
EGMapContainer1_init();
});
This is a deal killer at this point. Any solution?
Also, I’m running into a a huge problem with IE8. It doesn’t seem to execute the jQuery.post call at all. Really weird.
The problem for not executing the jquery post code is probably because there is an error. My question is, that function named ‘getListings’ is making use of map global variable (global.getBounds()) if that is so, how can you possibly get the bounds if the map isnt initialized?
Actually, the map SHOULD have been initialized because I was passing the function as an afterinit function:
$gMap->renderMap(array('getListings();'));
BUT, the problem is that even though the map was initialized, the tiles had not loaded so the bounds were not available. I solved this by:
$bc = new EGMapEvent('bounds_changed', 'getListings();', true, EGMapEvent::TYPE_EVENT_DEFAULT);
$tl = new EGMapEvent('tilesloaded', 'getListings();', true, EGMapEvent::TYPE_EVENT_DEFAULT);
$gMap->addEvent($bc);
$gMap->addEvent($tl);
$gMap->renderMap();
Works perfectly now.
Also, as for the jQuery.find problem, there is something bizarre with Internet Explorer. I had to resort to jQuery.filter. But then jQUery.filter had a problem with Firefox! I found a better solution. Instead of sending my data in XML format, I just send it as JSON. Problem solved. Plus, JSON is much faster than parsing xml anyway.
Sorry, missed the bracket after the getListings()…
Will be nice to see that code in action… thanks for sharing the hint about filter and find
I will be glad to share it once I’ve finished up re-factoring some things. Currently, it sucks as far as performance because each map change triggers a SQL query. What I’m working on now is:
Get the map bounds
Get the radius from center of map to NE bounds
Create a gmaps circle object that has a radius at least twice the radius of the current map boundaries. Get the bounds of the circle and then query listings for this larger area.
As the user moves around the map, if the map boundaries are still within the super boundary,don’t trigger a query. The data should be there.
I think this will really help performance by reducing the number of db queries.
Maybe the bounds_changed is the one causing the problem as I recalled that event to trigger multiple (http://stackoverflow.com/questions/4338490/google-map-event-bounds-changed-triggered-multiple-times-when-dragging)
Hi Nereia,
Now that I have a bit of time I have checked your question about ClearMarker. As you can see on the following code example:
$gMap->enableMarkerClusterer(new EGMapMarkerClusterer());
I created the EGMapMarkerClusterer without worrying at all about its ID. If you wish to make use of its functionality (clearMarkers is an example of it) you need to know its ID in order to build the function. For example,
$markerClusterer = new EGMapMarkerClusterer();
// attach this to the map
$gMap->enableMarkerClusterer($markerClusterer);
// create the function to clear Markers
$js = "function clearClusters(e) {
e.preventDefault();
e.stopPropagation();
".$markerClusterer->jsName().".clearMarkers();
}";
// include the function on the afterinit
$gMap->renderMap(array($js));
Now you can use the clearMarkers function see? Easy right?
Hope it helps
Hi Rangel,
Could you check if this piece of JS code suits your requirements or if it is causing the same problem as with the PHP code
// Make an array of the LatLng's of the markers you want to show
// for example....
var LatLngList = array (new google.maps.LatLng (52.537,-2.061), new google.maps.LatLng (52.564,-2.017));
// Create a new viewpoint bound
var bounds = new google.maps.LatLngBounds ();
// Go through each...
for (var i = 0, LtLgLen = LatLngList.length; i < LtLgLen; i++) {
// And increase the bounds to take this point
bounds.extend (LatLngList[i]);
}
// Fit these bounds to the map
map.fitBounds (bounds);
If it works for you, I will update the code to include a Fit to Bounds via JS
Thanks Antonio, I was able to do it in this way:
function clearMarkers(){
for(var i=0; i<markers.length; i++){
cluster.removeMarker(markers[i]);
markers.splice(i,1);
}
markers.length = 0; };
function makeAjaxRequest(lat,lon,n){
var center = EGMap0.getCenter();
var lt=lat;
alert("lat"+lt);
var lng=lon;
var nr=n;
// Create a cluster if it doesn't exist already
if(!cluster) {
cluster = new MarkerClusterer(EGMap0, {}); }
else clearMarkers();
for (var j=0; j<nr; j++) {
var latlng = new google.maps.LatLng(lt,lng);
var marker = new google.maps.Marker({ position: latlng,
title: "hola"});
// Add the marker to the markers array
markers.push(marker);
// Add the marker to the cluster
cluster.addMarker(marker);
markerAdded=true;
};
};
And in the php part:
$gMap->renderMap(array(‘makeAjaxRequest(lat,lon,n);’));
I haven’t finish yet because I’m working with Relational Active Queries in order to return the data to the AjaxRequest, and the next thing that I must do is reload the markers automatically for another purpose. I can choose who I want to see and this causes a markers reload but these people are moving and then periodically the markers must be uploaded… I don’t know if you understand what I’m trying to do.
I’ll share the code when it is done. I saw the function jQuery PeriodicalUpdater() http://www.360innovate.co.uk/blog/2009/03/periodicalupdater-for-jquery/
Any other suggestion will be appreciate!
Thanks
Sorry I had already tested it and it works great, I forgot to post here about it.
The zoom also leaves a margin so all the markers can be seen clearly, so it really works well.
Thanks for your reply!
So, do you think that apply this function to the core could be useful?