[GIS] Why is Openlayers KML-layer undefined when using permalink

javascriptkmlopenlayers-2vector

I am working on Openlayers to dynamically load KML tracks on map. I want it to load filtered KML everytime map is moved or zoomed based on viewport and zoom level.

I got it working with code below, but for some reason Permalink doesn't work anymore. When pressing permalink link Debug console gives error: Uncaught TypeError: Cannot set property 'loaded' of undefined on line 108. That is the line layer.loaded = false; on UpdateKmlLayer() function.

Could someone help on what I am missing here?

// Start position for the map (hardcoded here for simplicity)
var lat = 65.37371
var lon = 24.49389
var zoom = 6;

var map; //complex object of type OpenLayers.Map
var KMLlayer;

//Initialise the 'map' object
function init() {

    map = new OpenLayers.Map("map", {
        controls: [],
        maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
        maxResolution: 156543.0339,
        numZoomLevels: 16,
        units: 'm',
        projection: new OpenLayers.Projection("EPSG:900913"),
        displayProjection: new OpenLayers.Projection("EPSG:4326"),
        eventListeners: {
            "moveend": moveEnd,
        },

    });

    // Controls
    map.addControl(new OpenLayers.Control.Navigation());
    map.addControl(new OpenLayers.Control.PanZoomBar(), new OpenLayers.Pixel(0, 15));
    map.addControl(new OpenLayers.Control.Permalink());
    map.addControl(new OpenLayers.Control.ScaleLine({geodesic: true}));
    map.addControl(new OpenLayers.Control.MousePosition());
    map.addControl(new OpenLayers.Control.Attribution());


    // Osmarender
    layerTilesAtHome = new OpenLayers.Layer.OSM.Osmarender("Osmarender", {
        numZoomLevels: 18
    });
    map.addLayer(layerTilesAtHome);


    // Local KML
    KMLlayer = new OpenLayers.Layer.Vector("KMLlayer", {
        projection: map.displayProjection,
        strategies: [
            new OpenLayers.Strategy.BBOX(),
        ],
        protocol: new OpenLayers.Protocol.HTTP({
            url: "kml.php",
            format: new OpenLayers.Format.KML({
                extractStyles: true,
                extractAttributes: true
            })
        })
    });
    map.addLayer(KMLlayer);


    var switcherControl = new OpenLayers.Control.LayerSwitcher();
    map.addControl(switcherControl);
    switcherControl.maximizeControl();

    if (!map.getCenter()) {
        var lonLat = new OpenLayers.LonLat(lon, lat).transform(
            new OpenLayers.Projection("EPSG:4326"),
            map.getProjectionObject()
        );
        map.setCenter(lonLat, zoom);
    }
} //init() 


function moveEnd(event) {
    console.log(event.type);
    UpdateKmlLayer(KMLlayer);
}


function UpdateKmlLayer(layer) {
    console.log("updateKML");
    console.log(layer);
    layer.loaded = false;           // setting loaded to false unloads the layer
    layer.setVisibility(true);      // setting visibility to true forces a reload of the layer
    layer.refresh({ force: true, params: { 'zoom': map.getZoom()} });   // force new KML data
}

Best Answer

Cause:

When the permalink control is added to the map it registers for notification of the following events:

  • moveend
  • changelayer
  • changebaselayer

When you add the layerTilesAtHome layer to the map the changelayer or changebaselayer event if triggered and dispatched to the permalink control. The permalink control in turn recenters the map and set layer visibility accordingly to the permalink.

But by moving the map the permalink control triggers the moveend event which is dispatched to the moveEnd function. Unfortunately at this time the kmlLayer has not been created yet hence the error.

Solution 1 (recommended):

register the controls after all the layers have been added to the map.

Solution 2:

add a not-null check in the UpdateKmlLayer function:

function UpdateKmlLayer(layer) {
console.log("updateKML");
console.log(layer);
if(layer) {
   layer.loaded = false;           // setting loaded to false unloads the layer
   layer.setVisibility(true);      // setting visibility to true forces a reload of the layer
   layer.refresh({ force: true, params: { 'zoom': map.getZoom()} });   // force new KML data
}
}