4

I am using jQuery's getJSON method to load external line data I've created in QGIS.

What I'm trying to do is toggle my layers on and off - simple check boxes, no radio button for the basemap. I'd also like all the layers to be off when the map is initially loaded.

My code

var map=L.map('map').setView([41.9698, -87.6859], 12);

var basemap = L.tileLayer('http://a.tile.stamen.com/toner/{z}/{x}/{y}.png',
    {
      //attribution: would go here
      maxZoom: 17,
      minZoom: 9
    }).addTo(map);

//display geoJson to the map as a vector

var x = function(source, map)
{
var layers = L.geoJson(source,
    {

style: function(feature){
var fillColor, side=feature.properties.side;
    if (side==='Both') fillColor = '#309e2d';
    else if (side==='Neither') fillColor = '#d90f0f';
    else if (side==='West Only') fillColor = '#e27f14';
    else if (side==='East Only') fillColor = '#2b74eb';
    else if (side==='North Only') fillColor = '#eae42b';
    else if (side==='South Only') fillColor = '#552d04';
    else fillColor = '#f0f5f3';
    return { color: fillColor, weight: 3.5, opacity: null };
        },

onEachFeature: function(feature, geojson){
var popupText="<h1 class='makebold'>Border: </h1>"+feature.properties.name+"<br/>"+"<h1 class='makebold'>Which Side?: </h1>"+feature.properties.side;
geojson.bindPopup(popupText);
        }

    }).addTo(map);
};      

$.getJSON("data/Knox.geojson", function(source){ x(source, map); });
$.getJSON("data/abc.geojson", function(source){ x(source, map); });
$.getJSON("data/xyz.geojson", function(source){ x(source, map); });

I tried assigning a variable before the L.geoJson function (var layers), and then L.control.layers(null, layers).addTo(map); That doesn't seem to work.

How does one create a layer control for multiple external geojson's that are already associated with a few callback functions (L.geoJson, style, and onEachFeature)? Thanks in advance.

kadenz
  • 109
  • 2
  • 10

2 Answers2

1

EDIT:

Since you clarified that you want just the entire collection to be switched on/off, it is even more simple (and almost like what you tried by assigning your L.geoJson to var layers), but you have to take care of asynchronous processes.

To avoid this issue, you could do something like:

var myLayerGroup = L.layerGroup(), // do not add to map initially.
    overlays = {
        "Merged GeoJSON collections": myLayerGroup
    };

L.control.layers(null, overlays).addTo(map);

function x(source, map) {
    // Merge the GeoJSON layer into the Layer Group.
    myLayerGroup.addLayer(L.geoJson({}, {
        style: function (feature) { /* … */ },
        onEachFeature: function (feature, layer) { /* … */ }
    }));
}

$.getJSON("data/Knox.geojson", function(source){
    x(source, map);
});

Then myLayerGroup will be gradually populated with your GeoJSON features, when they are received from the jQuery getJSON requests and they are converted by L.geoJson.


If my understanding is correct, you would like the ability to switch on/off independently each feature from your GeoJSON data?

In that case, you would simply populate your layers object while building the L.geoJson layer group, e.g. inside the onEachFeature function:

var layers = {};

L.geoJson(source, {

    style: function (feature) { /* … */ },

    onEachFeature: function(feature, layer){
        var popupText = "<h1 class='makebold'>Border: </h1>" +
                feature.properties.name + "<br/>" +
                "<h1 class='makebold'>Which Side?: </h1>" +
                feature.properties.side;

        layer.bindPopup(popupText);

        // Populate `layers` with each layer built from a GeoJSON feature.
        layers[feature.properties.name] = layer;
    }

});

var myLayersControl = L.control.layers(null, layers).addTo(map);

If you have more GeoJSON data to load and to convert into Leaflet layers, simply do exactly the same (adding built layer into layers in onEachFeature function) and build the Layers Control only once at the end, or use myLayersControl.addOverlay(layer).

Note: make sure to structure your code to take into account your several asynchronous processes, if you load each GeoJSON data in a separate request. Refer to jQuery Deferred object. Or simply create your Layers Control first and use the addOverlay method.

If you want them to be initially hidden from the map, simply do not add the geoJson layer to the map…

Community
  • 1
  • 1
ghybs
  • 47,565
  • 6
  • 74
  • 99
  • Thanks @ghybs. I don't need to toggle layers based on features - I just want the entire layer to toggle on and off. I've added more getJSON methods to my above code at the bottom, because I'd like to control more than just one external geoJson. So far, I import the data (getJSON), and then 'draw' it with (L.geojson, style, and onEachFeature). As you suggested, I added `var layers={};` before L.geoJson and then `L.control.layers(null, layers).addTo(map);` at the end. My web inspector indicated, "Can't find variable 'layers' ", so I added an additional `var layers;` above `var x =function(`. – kadenz Nov 18 '15 at 16:44
  • The Layer Control window did show up (in the upper right), but the checkbox did not. So, I was not able still to switch it on and off. – kadenz Nov 18 '15 at 16:47
  • I see then it is even more simple. I will edit the above answer. – ghybs Nov 19 '15 at 02:04
  • Thanks again @ghybs. I've tried your suggestion, and I'm still unable to get it working. I've made a jsFiddle of my code here: http://jsfiddle.net/dbkaden/9c6uy5su/4/#&togetherjs=m47I792lhl – kadenz Nov 22 '15 at 17:25
  • Where is the code with `L.control.layers`? You access jsfiddle through **HTTPS**, which makes your browser block access to Leaflet files which are on HTTP only. You have to use an absolute path to your geojson file since the page does not execute from your server. Updated jsfiddle: http://jsfiddle.net/9c6uy5su/8/ – ghybs Nov 22 '15 at 17:40
  • Excellent! That works. Thank you. Before I answer my question, I have one followup: I would like to add additional geojsons with more getJSON methods. How do I modify `var myLayerGroup = L.layerGroup(), overlays = { "Merged GeoJSON collections": myLayerGroup };` so that each geojson layer toggles on and off? – kadenz Nov 22 '15 at 19:52
  • I tried `var overlays = { "Knox": 'data/Knox.geojson', "XYZ": 'data/XYZ.geojson' };` and then `overlays.addLayer(L.geoJson(` but that does not seem to allow me to toggle both Knox and XYZ on/off in separate check boxes. – kadenz Nov 22 '15 at 19:59
  • `myLayersControl.addOverlay(L.geoJson(/* … */), "new name")` http://leafletjs.com/reference.html#control-layers-addoverlay – ghybs Nov 23 '15 at 02:04
0

I learned a lot more about layer control in Leaflet than I expected, which is great. @ghybs offered really helpful suggestions.

My issue was about toggling external geoJson files on and off, particularly with the getJSON jQuery method. I was trying to assign a variable within my multiple callbacks, like:

var layers=L.geoJson(source,{ {style: /*....*/}, {onEachFeature: /*....*/}}

and then just going L.control.layers(null, layers).addTo(map);

That doesn't work (why? I still can't explain-I'm quite the beginner-programmer). The way I did get this to work was by creating my style and onEachFeature functions separately, like this:

function borders (feature){
var fillColor, side=feature.properties.side;
if (side==='Both') fillColor = '#309e2d';
else if (side==='Neither') fillColor = '#d90f0f';
else if (side==='West Only') fillColor = '#e27f14';
else if (side==='East Only') fillColor = '#2b74eb';
else if (side==='North Only') fillColor = '#eae42b';
else if (side==='South Only') fillColor = '#552d04';
else fillColor = '#f0f5f3';
return { color: fillColor, weight: 3.5, opacity: null };
    };

and

function popUp (feature, geojson){
var popupText="<h1 class='makebold'>
Border: </h1>"+feature.properties.name+"<br/>"+"<h1 class='makebold'>
Which Side</h1>"+feature.properties.side;geojson.bindPopup(popupText);
 };

and then assigning these directly as callbacks into the getJSON method. By doing it this way, I could create a variable before "drawing" my geoJson to the map with L.geoJson(). Then I could assign the variable dynamically(?) to the layer control:

$.getJSON("data/xyz.geojson", function(source){
var xyz = L.geoJson(source, {
    style: borders,
    onEachFeature: popUp});
togglelayer.addOverlay(xyz, 'This name shows up on the control')});
});

I stored the variable togglelayer like this:

var togglelayer = L.control.layers(null, null,{collapsed: false}).addTo(map);

This post was also helpful: How to add two geoJSON feature collections in to two layer groups


Community
  • 1
  • 1
kadenz
  • 109
  • 2
  • 10