Google Map v3 auto refresh Markers only

OK, I’ve got something working – largely a heavy refactoring of your original code – you will recognize various chunks.

$(function() {
    var locations = {};//A repository for markers (and the data from which they were constructed).

    //initial dataset for markers
    var locs = {
        1: { info:'11111. Some random info here', lat:-37.8139, lng:144.9634 },
        2: { info:'22222. Some random info here', lat:46.0553, lng:14.5144 },
        3: { info:'33333. Some random info here', lat:-33.7333, lng:151.0833 },
        4: { info:'44444. Some random info here', lat:27.9798, lng:-81.731 }
    };
    var map = new google.maps.Map(document.getElementById('map_2385853'), {
        zoom: 1,
        maxZoom: 8,
        minZoom: 1,
        streetViewControl: false,
        center: new google.maps.LatLng(40, 0),
        mapTypeId: google.maps.MapTypeId.ROADMAP
    });
    var infowindow = new google.maps.InfoWindow();

var auto_remove = true;//When true, markers for all unreported locs will be removed.

function setMarkers(locObj) {
    if(auto_remove) {
        //Remove markers for all unreported locs, and the corrsponding locations entry.
        $.each(locations, function(key) {
            if(!locObj[key]) {
                if(locations[key].marker) {
                    locations[key].marker.setMap(null);
                }
                delete locations[key];
            }
        });
    }

        $.each(locObj, function(key, loc) {
            if(!locations[key] && loc.lat!==undefined && loc.lng!==undefined) {
                //Marker has not yet been made (and there's enough data to create one).

                //Create marker
                loc.marker = new google.maps.Marker({
                    position: new google.maps.LatLng(loc.lat, loc.lng),
                    map: map
                });

                //Attach click listener to marker
                google.maps.event.addListener(loc.marker, 'click', (function(key) {
                    return function() {
                        infowindow.setContent(locations[key].info);
                        infowindow.open(map, locations[key].marker);
                    }
                })(key));

                //Remember loc in the `locations` so its info can be displayed and so its marker can be deleted.
                locations[key] = loc;
            }
            else if(locations[key] && loc.remove) {
                //Remove marker from map
                if(locations[key].marker) {
                    locations[key].marker.setMap(null);
                }
                //Remove element from `locations`
                delete locations[key];
            }
            else if(locations[key]) {
                //Update the previous data object with the latest data.
                $.extend(locations[key], loc);
                if(loc.lat!==undefined && loc.lng!==undefined) {
                    //Update marker position (maybe not necessary but doesn't hurt).
                    locations[key].marker.setPosition(
                        new google.maps.LatLng(loc.lat, loc.lng)
                    );
                }
                //locations[key].info looks after itself.
            }
        });
    }

    var ajaxObj = {//Object to save cluttering the namespace.
        options: {
            url: "........",//The resource that delivers loc data.
            dataType: "json"//The type of data tp be returned by the server.
        },
        delay: 10000,//(milliseconds) the interval between successive gets.
        errorCount: 0,//running total of ajax errors.
        errorThreshold: 5,//the number of ajax errors beyond which the get cycle should cease.
        ticker: null,//setTimeout reference - allows the get cycle to be cancelled with clearTimeout(ajaxObj.ticker);
        get: function() { //a function which initiates 
            if(ajaxObj.errorCount < ajaxObj.errorThreshold) {
                ajaxObj.ticker = setTimeout(getMarkerData, ajaxObj.delay);
            }
        },
        fail: function(jqXHR, textStatus, errorThrown) {
            console.log(errorThrown);
            ajaxObj.errorCount++;
        }
    };

    //Ajax master routine
    function getMarkerData() {
        $.ajax(ajaxObj.options)
          .done(setMarkers) //fires when ajax returns successfully
          .fail(ajaxObj.fail) //fires when an ajax error occurs
          .always(ajaxObj.get); //fires after ajax success or ajax error
    }

    setMarkers(locs);//Create markers from the initial dataset served with the document.
    //ajaxObj.get();//Start the get cycle.

    // *******************
    //test: simulated ajax
    /*
    var testLocs = {
        1: { info:'1. New Random info and new position', lat:-37, lng:124.9634 },//update info and position and 
        2: { lat:70, lng:14.5144 },//update position
        3: { info:'3. New Random info' },//update info
        4: { remove: true },//remove marker
        5: { info:'55555. Added', lat:-37, lng:0 }//add new marker
    };
    setTimeout(function() {
        setMarkers(testLocs);
    }, ajaxObj.delay);
    */
    // *******************
});

At the bottom of the code, you’ll find a testLocs dataset, demonstrating the range of possibilities for adding/removing/updating markers after the initial dataset has been applied.

I’ve not tested the ajax fully, but have simulated it with the testLocs dataset.

See DEMO

After 10 seconds, testLocs will be applied and you will see various changes to the markers (and the info displayed in the infowindow). Note in particular that update data doesn’t need to be complete – just specify the changes.

You will need to arrange for your server to :

  • build the initial dataset, following my locs example.
  • return JSON-encoded datasets, following the general format of my testLocs example.

EDIT 1

I have included all the client-side code necessary for fetching new datasets. All you need to do is :

  • create a server-side script (eg. “get_markers.php”) which returns a json-encoded dataset of the right format (as already exaplined).
  • edit the line url: "........", to point to the server-side script, eg url: "get_markers.php".
  • activate the cyclic ajax process by uncommenting the line ajaxObj.get();.
  • ensure the “simulated ajax” code block is commented out or removed.

EDIT 2

I have added a boolean “behavioural switch” named auto_remove. When set to true, a small additional block of code will run, causing all markers for unreported locs to be removed.

This will allow you to report all active markers at every iteration. Removals will happen automatically, without needing to actively command them.

The code which responds to { remove: true } is still in place, so (with auto_remove set to false) removals can be expressly commanded if you ever need to do so.

Updated DEMO

EDIT 3

The PHP script should build an array of the following form :

<%php
$testLocs = array(
    'loc1' => array( 'info' => '1. New Random info and new position', 'lat' => 0, 'lng' => 144.9634 ),
    'loc2' => array( 'lat'  => 0, 'lng' => 14.5144 ),
    'loc3' => array( 'info' => '3. New Random info' ),
    'loc5' => array( 'info' => '55555. Added', 'lat' => 0, 'lng' => 60 )
);
echo json_encode($testLocs);
exit();
%>

I’m not sure whether PHP will handle numeric keys. If not, then try strings, '1', '2' etc. It’s probably safest to give all keys an alphabetic prefix, eg. 'loc1', 'loc2' etc. Whatever you choose to do, make sure the keys in the javascript locs object are of the same type and composition.

Leave a Comment