mgul
mgul

Reputation: 742

Markers disappearing in google maps

I have a situation that is somewhat hard to explain, whence the approximative title (and I'm totally new at google maps API)

I created some markers in a google map with their javascript API (v3) and positioned them with gps coordinates coming from my own API. The issue is that when I get to the left border of the map (or right, as you want) those markers just disappear. I don't mean some custom borders that I've set, I mean the borders of the world. And when I go farther, they come back. They disappear when I cross one of those lines, as seen in this image:

google maps border

My markers are from the center of the map (Europe), it's like when I cross one of those line, let's say from the left just a little bit, the script starts to load the markers on the left map, which I don't see because I zoomed, and I'm still on the right map.

Sorry, quite hard to explain. Here's my complete script:

var map;
var markers = []; // this will hold all the markers on the map
// google maps API callback, we init the map
function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 30, lng: 10.3}, // FIXME
    zoom: 2, // default zoom
    styles: map_style, // dark style
    disableDefaultUI: false, // FIXME
    minZoom: 3, // the maximum zoom-out
    maxZoom: 15, // the maximum zoom-in: we can't set this to higher values because the pictures would be
                 // at their exact locations, if somebody takes a picture in his home, this would show the
                 // exact location of his home
  });

  // first time idle (when map is loaded) XXX: think about this design, can do better
  google.maps.event.addListenerOnce(map, 'idle', function(){
    // we get the gps coords of the current view's bounds
    var view_bounds = map.getBounds();
    var NE = view_bounds.getNorthEast();
    var SW = view_bounds.getSouthWest();

    // we need NW and SE but the API only gives us NE and SW, so a little bit of conversion...
    var NW = new google.maps.LatLng(NE.lat(), SW.lng());
    var SE = new google.maps.LatLng(SW.lat(), NE.lng());

    var tl_lat = NW.lat();
    var tl_long = NW.lng();
    var br_lat = SE.lat();
    var br_long = SE.lng();

    // get the newest pictures in those bounds
    get_newest_pictures(tl_lat, tl_long, br_lat, br_long);
  });

  // when the user stops dragging, check for pictures in the view bounds
  google.maps.event.addListener(map, 'dragend', function(e){
    // clear all markers
    deleteMarkers();

    // we get the gps coords of the current view's bounds
    // need North West lat & long, and South East lat & long
    var view_bounds = map.getBounds();
    var NE = view_bounds.getNorthEast();
    var SW = view_bounds.getSouthWest();

    // we need NW and SE but the API only gives us NE and SW, so a little bit of conversion...
    var NW = new google.maps.LatLng(NE.lat(), SW.lng());
    var SE = new google.maps.LatLng(SW.lat(), NE.lng());

    var tl_lat = NW.lat();
    var tl_long = NW.lng();
    var br_lat = SE.lat();
    var br_long = SE.lng();

    // get the newest pictures in those bounds
    get_newest_pictures(tl_lat, tl_long, br_lat, br_long);
  });
}

// get the newest pictures in an area (in bounds)
function get_newest_pictures(tl_lat, tl_long, br_lat, br_long) {

  var pictures;

  $.ajax({
    url: "http://127.0.0.1:6767/pictures/newest?tl_lat="+tl_lat
                                                        +"&tl_long="+tl_long
                                                        +"&br_lat="+br_lat
                                                        +"&br_long="+br_long,
    success: function(pictures) {
      // parse the return data in JSON
      pictures = JSON.parse(pictures);

      // for each pictures, create a marker at the location
      for (i = 0; i < pictures.length; i++) {
        var coords = new google.maps.LatLng(pictures[i]["gps_lat"], pictures[i]["gps_long"]);
        var marker = new google.maps.Marker({
          position: coords,
          title: "Hello World!",
          icon: "img/pin_newest.png"
        });
        marker["author"] = pictures[i]["author"];
        // push the marker in the markers array
        markers.push(marker);

        // set the marker
        marker.setMap(map);
      }

      console.log(markers);
    },
    error: function(XHR, textStatus, errorThrown) {
      console.log(textStatus);
      console.log(errorThrown);
    },
  });
}

// delete all the markers
function deleteMarkers() {
  for(i = 0; i < markers.length; i++){
    markers[i].setMap(null);
  }
  // empty the markers array
  markers = [];
}

I also tried to bound the map, but I don't think that's a good idea (and that wasn't working). Is there an "integrated" way to disable those infinite maps, to only have ONE map and not a bunch when I drag to borders? Or anything else that can fix this frustrating "error"?
Thank you!

EDIT: I'll try to give an example of what's happening.
This is what I want: I'm on a google map, I get the borders of the map to get where the user is looking, and in this area (delimited by the top left and bottom right corner which I've got) I want to load every picture that is in it. The pictures are saved with gps coordinates in my database.
Here are the 7 pictures I've got in my database:

 id | author | gps_lat  | gps_long
 ---+--------+----------+----------
 31 | user2  |  2.82717 |  95.98167
 32 | user2  | -8.52182 | -51.46316
 33 | user2  | 44.41541 | 143.46929
 34 | user3  | 22.15819 | -77.90592
 35 | user3  | 51.28558 |   9.05738
 36 | user4  | 22.08282 |   9.06114
 37 | user5  | -9.47497 | -46.55858

When I've got the pictures from my database, I want to display where they are to the user using markers. That's why I'm creating a marker at the place where the picture is for each picture. But the user only sees markers where he looks, so if a picture is at Brazil, and he looks at Europe, the response from the database wont even contain the picture at Brazil.

So at the end, I should have markers set in the area the user is looking, and only in this area.

Now that's what is happening: I've put some debug code to see the array of markers I have on the map, so I can see which picture I have. I've added console.log(markers.length); after of my for loop which sets all the markers to see how many marker I've got and compare this number to the number of markers I see. And this gave me I think informations about what's the problem. Here is what I see in a normal case:

normal1

Everything is normal, I've got 4 pictures in this area so the script displays me 4 markers. The console prints 4 for the console.log(markers.length);.

Now another normal case, but just "next to" when it bugs:

normal2

The console prints 2, so everything's fine.
But then, when I go like a few kilometers at the left, when I exit the "bounds" of the map to be on another map, here's what I've got:

bug

Nothing, as you can see. And the console prints 4. We see the border line on the map, it's a little bit dark because of the theme. I saw that when I overpass this border line, it starts bugging. It's like it tries to load the markers on the left map, but I'm still on the right map so I can't see them.

EDIT: Here is the server-side SQL query:

SELECT * FROM pictures
WHERE gps_long BETWEEN SYMMETRIC <tl_long> AND <br_long>
AND gps_lat BETWEEN SYMMETRIC <tl_lat> AND <br_lat>
ORDER BY date_taken DESC LIMIT 50;

Upvotes: 1

Views: 1903

Answers (1)

antonio
antonio

Reputation: 18262

Your problem is that your map's view is crossing the International Date Line (also called the anti-meridian) which is the 180 degrees longitude line.

When you approach this line coming from the east, longitudes go from 0 to -180, and when you approach this line coming from the west logitudes grow from 0 to 180.

So, when you get the map bounds including this line you are getting a bounds that looks like (using your variable names):

t1_long: 72
br_long: -72

And as your server code is expecting t1_long to be < br_long you are getting an array of markers that are out of the real bounds of your map (you are drawing markers that lay on the hidden side of the map).

You are not showing your server implementation but you need to take this into account. So, your implementation is OK when t1_long < br_long, but you need to add some conditions when t1_long > br_long. For example (pseudocode)

if (t1_long > br_long) {
    longitude_condition = " longitude > " + t1_long " and longitude < 180 or longitude < " + br_long + " and longitude > -180 ";
}

Update:

I'm adding an image to illustrate my point:

enter image description here

According to your query, when your map bounds are like in the picture (the red square) you are querying:

WHERE gps_long BETWEEN SYMMETRIC 100 AND -90

And thus, the query is returning the green marker as -90 < -70 < 100 instead of the pink marker.

The SYMMETRIC operator in this case doesn't solve the problem because it only allows the -90 and 100 limit order to be irrelevant. so both WHERE gps_long BETWEEN SYMMETRIC 100 AND -90 and WHERE gps_long BETWEEN SYMMETRIC -90 AND 100 are true for the green marker and false for the pink one.

Update:

if (t1_long > br_long) {
    SELECT * FROM pictures
    WHERE (gps_long BETWEEN SYMMETRIC <tl_long> AND 180 OR gps_long BETWEEN SYMMETRIC <br_long> AND -180)
    AND gps_lat BETWEEN SYMMETRIC <tl_lat> AND <br_lat>
    ORDER BY date_taken DESC LIMIT 50;
} else {
    SELECT * FROM pictures
    WHERE gps_long BETWEEN SYMMETRIC <tl_long> AND <br_long>
    AND gps_lat BETWEEN SYMMETRIC <tl_lat> AND <br_lat>
    ORDER BY date_taken DESC LIMIT 50;
}

Upvotes: 2

Related Questions