Search code examples
restdictionaryashxbing-maps

Initialising multiple Bing maps with pushpins on a page with REST services


I am trying to display multiple bing maps on the same page, with each map having a specified location displayed based on a geocode.

The issue I am having is this...

  • When I display one map and intialise it with a location - that is fine.
  • When I run the same action multiple times consecutively to multiple map divs it does not display correctly - often just the last map intialised is displayed (sometimes it is quite random though, with two being displayed and sometimes with the locations mixed up).
  • Funnily enough, if I pause between each map initialisation by bringing up an alert it all works fine (In my example below just uncomment the alerts and you can see). This seems to happen in FF and not IE for some reason I have just noticed.

I built a single page html example based on the msdn example provided. The whole markup is below, copied and saved as an html file it should work as mentioned above. I just whipped this up for ease of understanding and better communication with my question.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
   <head>
      <title></title>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

      <script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>

      <script type="text/javascript">

         var map = null;
         var mapId = '';
         var geocode = ''

         function InistionaliseMaps()
         {
            //alert('1');
            InistialiseMap('mapDiv1', 'London');
            //alert('2');
            InistialiseMap('mapDiv2', 'Barcelona');
            //alert('3');
            InistialiseMap('mapDiv3', 'Auckland');
            //alert('4');
            InistialiseMap('mapDiv4', 'New York');
            //alert('5');
            InistialiseMap('mapDiv5', 'Amsterdam');
         }

         function InistialiseMap(mId, gc)
         {
            mapId = mId;
            geocode = gc;

            GetMap();
            ClickGeocode();
         }

         function GetMap()
         {
            // Initialize the map
            map = new Microsoft.Maps.Map(document.getElementById(mapId),{credentials:"Auy_rZ68nbxt5cE4EYg7o1pFD3IpEg6sgNNWC8RyP04f12t9GSf0YQzlnBmgyJV3", mapTypeId:Microsoft.Maps.MapTypeId.road}); 

         }

         function ClickGeocode(credentials)
         {
            map.getCredentials(MakeGeocodeRequest);
         }

         function MakeGeocodeRequest(credentials)
         {

            var geocodeRequest = "http://dev.virtualearth.net/REST/v1/Locations?query=" + encodeURI(geocode) + "&output=json&jsonp=GeocodeCallback&key=" + credentials;

            CallRestService(geocodeRequest);
         }

         function GeocodeCallback(result) 
         {
            alert("Found location: " + result.resourceSets[0].resources[0].name);

            if (result &&
                   result.resourceSets &&
                   result.resourceSets.length > 0 &&
                   result.resourceSets[0].resources &&
                   result.resourceSets[0].resources.length > 0) 
            {
               // Set the map view using the returned bounding box
               var bbox = result.resourceSets[0].resources[0].bbox;
               var viewBoundaries = Microsoft.Maps.LocationRect.fromLocations(new Microsoft.Maps.Location(bbox[0], bbox[1]), new Microsoft.Maps.Location(bbox[2], bbox[3]));
               map.setView({ bounds: viewBoundaries});

               // Add a pushpin at the found location
               var location = new Microsoft.Maps.Location(result.resourceSets[0].resources[0].point.coordinates[0], result.resourceSets[0].resources[0].point.coordinates[1]);
               var pushpin = new Microsoft.Maps.Pushpin(location);
               map.entities.push(pushpin);
            }
         }

         function CallRestService(request) 
         {
            var script = document.createElement("script");
            script.setAttribute("type", "text/javascript");
            script.setAttribute("src", request);
            document.body.appendChild(script);
         }

      </script>
   </head>
   <body onload="InistionaliseMaps();">
      <div id='mapDiv1' style="position:relative; width:400px; height:400px;"></div>
      <div id='mapDiv2' style="position:relative; width:400px; height:400px;"></div>
      <div id='mapDiv3' style="position:relative; width:400px; height:400px;"></div>
      <div id='mapDiv4' style="position:relative; width:400px; height:400px;"></div>
      <div id='mapDiv5' style="position:relative; width:400px; height:400px;"></div>    
   </body>
</html>

I believe this is probably occurring as the page is loading to fast and the consecutive calls to the REST service are overlapping, or an object used in the REST service is not being destroyed before the next call or something like that. I really am a tad confused to be honest.

If anyone knows what might be going on here, a way around the problem or a better way to do this via Bing maps - it would be much appreciated and I shall be forever in your stack-debt. Thanks.


Solution

  • I have not tried out your code, via inspection I think I spotted some problems that would cause the behavior you are seeing. The problem has to do with you using a global variable to reference your map in GeocodeCallback(). GeocodeCallback() is a callback function that is run after the geocoding is complete, there is no guaratee that if you issue multiple CallRestService()s , GeocodeCallback() for each request will be called in the same sequence. You set the map variable to your current map in GetMap(), and then proceed to call CallRestService(), and then subsequently call InistialiseMap() again, which will override the map variable with a new map. If GeocodeCallback() is called before InistialiseMap(), you will have no problems.(As illlustrated by the use of alerts which most likely forces this to happen). However, chances are multiple InistialiseMap() are run before the GeocodeCallback()s are called, so there is no determining which map gets updated with the geocoding results returned by GeocodeCallback().

    Here is an easy solution to your problem. Not very elegant and I haven't tested the code, but the idea is to have a separate geocode callback for each map, as well is storing each map in its own varable.

      <script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
    
      <script type="text/javascript">
    
         var mapOne = null;
         var mapTwo = null;
         var geocode = ''
    
         function InistionaliseMaps()
         {
            InistialiseMap('mapDiv1', mapOne, 'London');
            InistialiseMap('mapDiv2', mapTwo,'Barcelona');
         }
    
         function InistialiseMap(mId, mapVar, gc)
         {
            geocode = gc;
    
            GetMap(mId, mapVar);
            ClickGeocode(mapVar);
         }
    
         function GetMap(mapIdName, mapVar )
         {
            // Initialize the map
            mapVar = new Microsoft.Maps.Map(document.getElementById(mapId),{credentials:"Auy_rZ68nbxt5cE4EYg7o1pFD3IpEg6sgNNWC8RyP04f12t9GSf0YQzlnBmgyJV3", mapTypeId:Microsoft.Maps.MapTypeId.road}); 
        mapVar.MapIdName = mapIdName ;
         }
    
         function ClickGeocode(mapVar )
         {
            mapVar.getCredentials(MakeGeocodeRequest)
         }
    
         function MakeGeocodeRequest(credentials)
         {
            // Figure out how to get the map that called this...
            var mapThatCalledThis = ...
            var geocodeRequest = "http://dev.virtualearth.net/REST/v1/Locations?query=" + encodeURI(geocode) + "&output=json&jsonp=GeocodeCallback"+mapThatCalledThis .MapIdName+"&key=" + credentials;
    
            CallRestService(geocodeRequest);
         }
    
         function GeocodeCallbackmapDiv1(result) 
         {
               // common stuff
               mapOne.entities.push(pushpin);
            }
         }
         function GeocodeCallbackmapDiv2(result) 
         {
               // common stuff
               mapTwo.entities.push(pushpin);
            }
         }
         function CallRestService(request) 
         {
            var script = document.createElement("script");
            script.setAttribute("type", "text/javascript");
            script.setAttribute("src", request);
            document.body.appendChild(script);
         }
    
      </script>
    


    Good luck.