Google Maps and jQuery – loading markers when user moves the map
Recently I was working on a project, in which the goal was to display all company branches within a certain distance, defined by a zip code and a range provided by user input. The solution was pretty simple. A user provides a zip code and the distance range, the script translates the zip code into geographical length and by using the Haversine formula retrieves all branches from the database and displays them in a Google map. This script was only working when a user submitted the information through a form that was provided for this script. As soon as he or she started to play with the Google map, the information about company's branches outside the initial zip code entered were not updated. When one assumes that a company has for instance 1000 Branches and resides in a small country, displaying other branches, while a user is moving within the Google map may be crucial to their search. I had to come up with an idea, how to solve this problem in my jQuery code. This is my solution.
First of all, I had to decide how to handle this event. One possibility was to write my own event listener and trigger it using GEvent.trigger() method. One of the pre-build events provided "out of the box" by Google Map API is "moveend". Using this event, we can send an AJAX request every time a user moves the map, either when he or she drags and drops it or he or she is using provided controls. This approach has definite disadvantages because it might be possible that a user will play with a map a lot and this will lead to several AJAX requests every time he or she does that. On the other hand, you also need to assume that since a user is using the form you provided him or her in the first place, this situation probably won't be that common.
One thing we need to make a decision about before we will start coding is when we should use the Haversine formula and when we should display the markers according to the borders of the map. According to this study, using the Haversine formula in a web query on a MySQL database with 800k entries might take up to 8 seconds. Therefore it will be crucial to split our jQuery code into requests concerning retrieving the data based on the Haversine formula and data within the borders of the map. In this example I won't give a complete walk through of how to measure the distance between two points (it will probably be a good subject for another example). In this example I will only show how to display data on an "moveend" event.
Let's take a look at the code. In line 1, we are executing the code after the document is loaded. I would consider it a standard procedure in writing unobtrusive JavaScript. In line 2, we define our map container, which corresponds with a HTML tag whose id equals map. In line 3, we are checking if the user’s browser is compatible with Google Map API and if it is, and our map container also exists, we can finally execute the rest of the code.
In line 5, we are instantiating our Google map and in lines 6 and 7 we are defining some controls for our map, the center (GLatLng) and zoom level (14). In line 9, we would have our code to measure the distance from given zip code and to display the markers on our map. The most interesting part of our code starts in line 14. We add a listener, which triggers on "moveend" event. In line 15, we use the getBounds() method, which returns GLatLngBounds object for us. In lines 16 to 19, we use getSouthWest() and getNorthEast() methods of our GLatLngBounds objects. This methods return GLatLng object, therefore we can directly use its methods to retrieve the geographical lengths of our south west and northeast corner. The last part is pretty simple, and I will leave it to you to adjust it to your needs. In line 20, we use the AJAX request, and we pass all geographical lengths to our php file. We assume that the response will be a valid json_encode() representation of the data retrieved from the database, and in lines 21 to 23, we add our markers to the map.
Here is the code you have been waiting for:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | $(document).ready(function() { var mapContainer = $('#map')[0]; if (GBrowserIsCompatible()) { if (mapContainer) { var map = new GMap2(mapContainer); map.addControl(new GLargeMapControl); map.setCenter(new GLatLng(52.519015140666,13.419671058654785), 14); $('#submit').click(function() { // here goes the code handling calculatig of distance // truncated because it is not a part of this post GEvent.addListener(map, "moveend", function() { var bounds = this.getBounds(); var swLat = bounds.getSouthWest().lat(); var swLng = bounds.getSouthWest().lng(); var neLat = bounds.getNorthEast().lat(); var neLng = bounds.getNorthEast().lng(); $.getJSON('helper.php', { swLat: swLat, swLng: swLng, neLat: neLat, neLng: neLng }, function(data) { var point = new GLatLng(data.lat, data.lng); var marker = new GMarker(point); map.addOverlay(marker); }); }); }); } } }); |
You might ask why we are placing this code inside of jQuery's click event? The answer is simple. This way we can prevent triggering the "moveend" event, before a user uses the form. Only after he or she uses the form, our listener will react to the user's interaction with the map.
Another question might be, why we are not using GBounds.extend() method to adjust the zoom level? An answer for this question is as simple as the last one. We already defined the zoom level by passing the geographical lengths of our rectangle to the php file and since we triggered "moveend" event, we always have an actual part of the map, which a user is seeing at the point of triggering it.
I hope you will like this example. I did not want to provide the whole code for this example, because first of all I wanted to split it into two entries and second of all, I did not want to provide an example which you can copy and past, but rather give a solution for a certain problem and possibility start a discussion about doing it better. Have fun with this one.
July 22nd, 2009 - 14:37
Hi dear, how are you? i hope you will be fine and in the best of your health. Dear, i just comment you to say that you have done what a great job here in this unique blog. your blog is very much stunning and also according to the desire of the readers. I really appreciate your efforts. Thanks a lot for providing us such a great information.