0

I'm working on a implementing a Google map on a website with our own tiles overlays and KML elements. I've been previously requested to create code so that, for instance, when the page is loaded from a specific URL, it would initialize with one of the tile overlays already enabled. Recently, I've been requested to do the same for the buildings which are outlined by KML elements so that, arriving at the page with a specific URL, it would automatically zoom, center, and display information on the building.

However, while starting with the tile overlays work, the building KML does not. After doing some testing, I've determined that when the code which checks the URL executes, the page is still loading the KML elements and thus do not exist for the code to compare to or use:

Code for evaluating URL (placed at the end of onLoad="initialize()")

function urlClick() {
    var currentURL = window.location.href; //Retrieve page URL
    var URLpiece = currentURL.slice(-6);   //pull the last 6 digits (for testing)
    if (URLpiece === "access") {           //If the resulting string is "access":
        access_click();                      //Display accessibility overlay
    } else if (URLpiece === "middle") {    //Else if the string is "middle":
        facetClick('Middle College');        //Click on building "Middle College"
    };
};

facetClick();

function facetClick(name) {  //Convert building name to building ID.
    for (var i = 0; i < active.placemarks.length; i++) {
        if (active.placemarks[i].name === name) {
            sideClick(i)     //Click building whose id matches "Middle College"
        };
    };
};

Firebug Console Error

active is null
for (var i = 0; i < active.placemarks.length; i++) {

active.placemarks is which KML elements are loaded on the page, and being null, means no KML has been loaded yet. In short, I have a mistiming and I can't seem to find a suitable place to place the URL code to execute after the KMl has loaded. As noted above, I placed it at the end of onLoad="initialize()", but it would appear that, instead of waiting for the KML to completely load earlier in the function, the remainder of the function is executed:

onLoad="initialize()"

information();   //Use the buttons variables inital state to set up description
buttons();       //and button state
button_hover(0); //and button description to neutral.

//Create and arrange the Google Map.

//Create basic tile overlays.

//Set up parser to work with KML elements.
myParser = new geoXML3.parser({ //Parser: Takes KML and converts to JS.
    map: map,                   //Applies parsed KML to the map
    singleInfoWindow: true,
    afterParse: useTheData      //Allows us to use the parsed KML in a function
});
myParser.parse(['/maps/kml/shapes.kml','/maps/kml/shapes_hidden.kml']);
google.maps.event.addListener(map, 'maptypeid_changed', function() {
    autoOverlay();
});

//Create other tile overlays to appear over KML elements.

urlClick();

I suspect one my issues lies in using the geoxml3 parser (http://code.google.com/p/geoxml3/) which converts our KML files to Javascript. While the page has completed loading all of the elements, the map on the page is still loading, including the KML elements. I have also tried placing urlClick() in the parser itself in various places which appear to execute after all the shapes have been parsed, but I've had no success there either.

While I've been intending to strip out the parser, I would like to know if there is any way of executing the "urlClick" after the parser has returned the KML shapes. Ideally, I don't want to use an arbitrary means of defining a time to wait, such as "wait 3 seconds, and go", as my various browsers all load the page at different times; rather, I'm looking for some way to say "when the parser is done, execute" or "when the Google map is completely loaded, execute" or perhaps even "hold until the parser is complete before advancing to urlClick".


Edit: Here are links to the map with the basic form of the issue found above. Since I've been developing the next update to the map on a test server, facetClick() is not part of this live version and I instead use its output function sideClick(); however the error is still the same in this arrangement:

active is null
google.maps.event.trigger(active.gpolygons[poly],'click');

Map: http://www.beloit.edu/maps/

Map w/Accessibility: http://www.beloit.edu/maps/?access

Map w/Building Click: http://www.beloit.edu/maps/?middle


EDIT: Spent most of my day working on rebuilding the functionality of the parser in Javascript and, low and behold, without the parser it works just fine. I figure that is obvious as I have to define each shape individually before the code, rather than waiting for it to be passed along by the parser. It would seem the answer is "if you want unique URLs, drop the parser". >_<

Nick Mischler
  • 175
  • 5
  • 22
  • What is your "useTheData" function? You should be able to do this with geoxml3, but without a complete example (preferably a link to your (or a) map that exhibits the issue it will be difficult to guide you. – geocodezip Jun 06 '12 at 05:16
  • @geocodezip useTheData runs through the active placemarks and creates a list of their names in alphabetical order outside of the map; allowing a user to search and find a building by it's name. As for an example/complete map, I'll give a link when I get to the office; home at the moment. – Nick Mischler Jun 06 '12 at 13:41
  • @geocodezip Links to the map have been added; please see the edit above. – Nick Mischler Jun 06 '12 at 14:20
  • so to clarify, you want everything on the map to load first and then after it has loaded you want to be able to execute a function? – Suvi Vignarajah Jun 06 '12 at 19:15
  • @Suvi While I thank you for your interest in the problem, I've been told that there is no interest here in having such a feature. -_-' Nevertheless, I still think it would be nice to have, so yes, that is the issue. The KML from the parser has yet to be completed when the code which would "click" the shape executes at the end of the initialize function; thus, having the map completely load first, and then this code execute, would be a viable solution. My issue is, how to do this dynamically rather than specifying a specific time. – Nick Mischler Jun 06 '12 at 19:22
  • I despise when requirements change as well, however I think I may have a solution for this issue. Let me provide it in the answer so it may be of use to others as well. – Suvi Vignarajah Jun 06 '12 at 19:39

1 Answers1

1

I've come across a similar problem when dealing with waiting for markers and infoWindows to load before executing a function. I found a solution here ( How can I check whether Google Maps is fully loaded? see @Veseliq's answer) that using the google maps event listener function for checking when the map is 'idle', does the trick. I assume this solution would work for KML layers as well. Essentially what you will have to do is include the following at the end of your initialize function:

google.maps.event.addListenerOnce(map, 'idle', function(){
    // do something only the first time the map is loaded
});

In the API reference ( https://developers.google.com/maps/documentation/javascript/reference ) it states that the 'idle' event "is fired when the map becomes idle after panning or zooming". However, it seems to hold true that it is also fires on initial page load after everything in the map_canvas has loaded. And by using the addListenerOnce call, you ensure that it is never executed again after the initial page load (meaning it won't fire after a zoom or a pan action).


Second option:
As I mentioned you can take the callback approach, I believe this will only call your urlClick function after completing the parsing. Here's how you should probably arrange your code to make it work:

function someFunction(callback){
    myParser.parse(['/maps/kml/shapes.kml','/maps/kml/shapes_hidden.kml']);
    callback();
}

and then in your initialize you will have:

someFunction(function(){
    urlClick();
});

You will have to make your map and myParser variables global.

Resources: This link had an excellent and detailed brief on how callback functions work in javascript, http://www.impressivewebs.com/callback-functions-javascript/

Community
  • 1
  • 1
Suvi Vignarajah
  • 5,758
  • 27
  • 38
  • That is a very ideal solution; however, in testing it I come across one little issue. When I run it in Firefox- which is apparently weighed down by something for it is dreadfully slow- it works. However, if I try it in the much faster Chrome, I receive the same error. I assume that, since the parser is not part of the map itself and instead simply adds/passes shapes to the map, if the map completely loads what it has internally and hits idle before the parser is done parsing, I still get the "active is null" error. It would seem that this route of delaying based on the map won't work. >_ – Nick Mischler Jun 06 '12 at 20:09
  • Interesting, I did not notice that the layer the parser creates was independent of the map itself. If this is the case, then you can probably achieve this by putting the `myParser.parse(['/maps/kml/shapes.kml','/maps/kml/shapes_hidden.kml']);` in a separate function, then calling the `urlClick()` function as a callback to the other one. I will update my answer. – Suvi Vignarajah Jun 06 '12 at 20:41
  • Oh, that's an interesting technique; I'll have to try and remember it. This has the opposite effect however, for reasons I can not guess the reason for, in that it works in Chrome, but not in Firefox. (Un)fortunately, removing the parser appears to work perfectly and, while I thank you for your assistance, I feel removing the parser will do much more good than leaving it in with some tricky fix to make unique urls. At the very least, I've learned a few things. ;3 – Nick Mischler Jun 07 '12 at 14:49