8

I'm using Google Maps V3 to display some pins. I want to be able to refresh markers without affecting where you're at on the map or the zoom level. I want the markers to be updated every x seconds.

How would I go about doing this? I don't have that much experience with jQuery/ajax.

A working example of my map is below.

http://jsfiddle.net/dLWNc/

 var locations = [
  ['some random info here', -37.8139, 144.9634, 1],
  ['some random info here', 46.0553, 14.5144, 2],
  ['some random info here', -33.7333, 151.0833, 3],
  ['some random info here', 27.9798, -81.731, 4],    ];


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 marker, i;

for (i = 0; i < locations.length; i++) {  
  marker = new google.maps.Marker({
    position: new google.maps.LatLng(locations[i][1], locations[i][2]),
    map: map
  });

  google.maps.event.addListener(marker, 'click', (function(marker, i) {
    return function() {
      infowindow.setContent(locations[i][0]);
      infowindow.open(map, marker);
    }
  })(marker, i));
}

Thank you

chillers
  • 1,447
  • 2
  • 15
  • 25
  • you want to refresh markers (delete them and then add new ones) or just update their location? – pwolaq Feb 08 '13 at 11:43
  • as far as I am not wrong, all you have to do is overwrite locations array with new data – pwolaq Feb 08 '13 at 11:55
  • To make changes to existing `locations` you will need to arrange for each one to have a unique id, by which it can be addressed. The ids will need to be generated by the server. If you can't do this, then you will have to replace all `locations` (though not necessarily all the corresponding Markers) at every iteration. – Beetroot-Beetroot Feb 08 '13 at 11:59
  • As long as (a) your 1 - 4 are ids and not just indexes and (b) the server can always address each location (hence the associated Marker) via the same unique id on every occasion, then you have the basis for making selective updates, rather than total replacement. Selective updates will require more programming effort, so if the number of locations is small, it is maybe more realistic to opt for total replacement. – Beetroot-Beetroot Feb 08 '13 at 12:14
  • Daniel, yes, on the assumption that only a handful of markers will be affected at each iteration, then for 2000 markers you should definitely perform selective updates. What you say about id generation is good. Existing markers can always be re-addressed by the same id, and new markers will receive a new previously unallocated id - perfect. I've not got time to help with the code right now but will look in later today (in several hours). – Beetroot-Beetroot Feb 08 '13 at 12:30
  • Now the ground-rules are established, maybe @Pawel_W will be able to help sooner than I. – Beetroot-Beetroot Feb 08 '13 at 12:37

1 Answers1

22

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.

Beetroot-Beetroot
  • 18,022
  • 3
  • 37
  • 44
  • I would like as if I want to update specific markers depends on json object id and remain other markers position. – StoledInk Jul 22 '16 at 01:56
  • Isn't it ** – ggdx Sep 15 '16 at 17:52
  • Somehow I never got the php part to work.. I see the php being pulled from the server but it doesn't update the markers (just removes all). I also put the php output as a test.json and again, i see it pulled from the webserver as mime type json but nothing happens in the map. It doesn't display any errors in the console. – Alex van Es Jan 31 '21 at 04:01