[GIS] How to render Multi-Response GeoJSON tiles

geojsonleafletrenderingvector-tiles

I am using TileStache to combine and server multiple vector layers in a single Mutli-Response GeoJSON tile, which is basically all my individual tiles/layers (GeoJSONs containing either roads, pois, buildings) merged into one.

When TileStache combines the layers, the original layer name (like "roads" or "pois") is added before the features of that layer are included in the GeoJSON, so when I parse the tile to render it in leaflet (using the TileLayer.GeoJSON plugin) it doesn't recognize the objects in the GeoJSON file. It just skips over them and doesn't render anything.

This is what the sample response looks like:

{
    "roads": {
        "type": "FeatureCollection",
        "features": [{
            "geometry": {
                "type": "LineString",
                "coordinates": [
                    [73.12500, 33.61371],
                    [73.12432, 33.61462]
                ]
            },
            "type": "Feature",
            "id": "ff7274b342",
            "clipped": true,
            "properties": {
                "priority": 5.00000,
                "name": "Islamabad Highway"
            }
        }]
    },
    "boundary": {
        "type": "FeatureCollection",
        "features": []
    },
    "pois": {
        "type": "FeatureCollection",
        "features": [{
            "geometry": {
                "type": "Point",
                "coordinates": [73.10332, 33.60876]
            },
            "type": "Feature",
            "id": "0d39282b10",
            "clipped": true,
            "properties": {
                "priority": 1,
                "name": "BENAZIR BHUTTO INTERNATIONAL AIRPORT ISLAMABAD"
            }
        }]
    },
    "cartographic": {
        "type": "FeatureCollection",
        "features": [{
            "geometry": {
                "type": "MultiPolygon",
                "coordinates": 
                    [

                        [
                            [73.10095, 33.61462],
                            [73.10065, 33.61438],
                            [73.09731, 33.61462],
                            [73.10095, 33.61462]
                        ]
                    ]
            },
            "type": "Feature",
            "id": "963cec5810",
            "clipped": true,
            "properties": {
                "category": 6,
                "priority": 5,
                "kind": "port places",
                "name": "BENAZIR BHUTTO INTERNATIONAL AIRPORT"
            }
        }
}

And this is the code I am using in Leaflet:

var geojsonURL1 = 'http://localhost:8080/composite/{z}/{x}/{y}.json'; 
var geojsonTileLayer1 = new L.TileLayer.GeoJSON(geojsonURL1, { maxZoom:22,
        //clipTiles: true,
        unique: function (feature) {
            return feature.id; 
        }
    }, {
        style: style,
        onEachFeature: function (feature, layer) {
            if (feature.properties) {
                var popupString = '<div class="popup">';
                for (var k in feature.properties) {
                    var v = feature.properties[k];
                    popupString += k + ': ' + v + '<br />';
                }
                popupString += '</div>';
                layer.bindPopup(popupString);
            }
            if (!(layer instanceof L.Point)) {
                layer.on('mouseover', function () {
                    layer.setStyle(hoverStyle);
                });
                layer.on('mouseout', function () {
                    layer.setStyle(style);
                });
            }
        }
    }
);

map.addLayer(geojsonTileLayer);

How can I render them in Leaflet? Are there any viable alternatives to render the GeoJSON tiles?

Best Answer

The so-called "multiresponse GeoJSON object" is not valid GeoJSON. Split the data before instantiating the Leaflet GeoJSON layers, e.g.:

// Assuming that you've already fetched the data off the network
var data = {
  roads: {
    type: "FeatureCollection",
    features: .....
  },
  pois: {
    type: "FeatureCollection",
    features: .....
  },
  .......
};

for (var featureLayer in data) {
    console.log(featureLayer); // e.g. "roads", "pois", etc
    var geoJson = data[featureLayer]; // This is now a valid geojson object

    // Now we can spawn Leaflet layers based on valid GeoJSON
    var layer = L.geoJson(geoJson, {...}).addTo(map);
}