azureazure-mapsvector-tilestippecanoe

Display Vector Tile (PBF) in Azure Maps


I am using Azure Maps, and want to display vector tiles that I have generated with tippecanoe.

I was initially getting an error in Azure Maps in the frontend javascript, which was basically complaining the generated pbf were not acceptable, because it was compressed. I fixed that.

Now, the frontend javascript does not throw any error, except when it cannot find a z/x/y pbf file.

When it does not throw any errors in the javascript console.log, it does not display any vector from the vector tile pbf.

What I think I am not getting right is the sourceLayer that goes into the javascript.

<script type="text/javascript">
        function InitMap() {
        console.log("Hi from InitMap")
            var map = new atlas.Map('myMap', {
                center: [-122.33, 47.6],
                zoom: 12,
                language: 'en-US',
                authOptions: {
                    authType: 'subscriptionKey',
                    subscriptionKey: '<My Azure Maps Key>'
                }
            });

            //Wait until the map resources are ready.
            map.events.add('ready', function () {
                //Create a vector tile source and add it to the map.
                datasource = new atlas.source.VectorTileSource(null, {
                    tiles: ['http://127.0.0.1:8080/api/file/{z}/{x}/{y}.pbf'],
                    maxZoom: 12
                });
                map.sources.add(datasource);

                var buildingLayer = new atlas.layer.PolygonLayer(datasource, null, {
                    sourceLayer: 'Feature',
                    fillColor: 'red',
                    fillOpacity: 0.7
                });
                map.layers.add(buildingLayer, 'labels');
            });
        }
    </script>

This is my Spring Boot that serves the Vector Tiles (PBFs) that were generated thru tippecanoe:

@ResponseBody
@CrossOrigin
@GetMapping("api/file/{z}/{x}/{y}.pbf")
public ResponseEntity<Resource>getPbf(
            @PathVariable("z") int z,
            @PathVariable("x") int x,
            @PathVariable("y") int y,
            HttpServletResponse httpServletResponse
        ) throws FileNotFoundException {
    
    File file = new File(String.format("/home/markus/Documents/AssessorTilesNotZipped/%d/%d/%d.pbf", z, x, y));
    System.out.println("Z: " + String.valueOf(z) + ", X: " + String.valueOf(x) + ", Y: " + String.valueOf(y));
    HttpHeaders headers = new HttpHeaders();
    String filename = file.getName();
    headers.add("Content-disposition", "attachment; filename=" + filename);
    Resource resource = new InputStreamResource(new FileInputStream(file));
    return ResponseEntity.ok()
            .headers(headers)
            .contentLength(file.length())
            .contentType(MediaType.parseMediaType("application/x-protobuf"))
            .body(resource);
}

As I said, I think what I am not able to get it right is the sourceLayer in the Javascript. So, below is a sample of the JSON that I used to generate the PBF with tippecanoe.

> {
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "FIPS_CODE": 8009, "PARCEL_APN": null, "TAXAPN": null, "SITE_HOUSE_NUMBER": null, "SITE_DIRECTION": null, "SITE_STREET_NAME": null, "SITE_MODE": null, "SITE_QUADRANT": null, "SITE_UNIT_PREFIX": null, "SITE_UNIT_NUMBER": null, "SITE_CITY": null, "SITE_STATE": null, "SITE_ZIP": null, "SITE_PLUS_4": null, "_X_COORD": -102.554234, "_Y_COORD": 37.057221, "ADDR_SCORE": null, "OWNER_NAME_1": null, "OWNER_NAME_2": null, "MAIL_HOUSE_NUMBER": null, "MAIL_DIRECTION": null, "MAIL_STREET_NAME": null, "MAIL_MODE": null, "MAIL_QUADRANT": null, "MAIL_CITY": null, "MAIL_STATE": null, "MAIL_ZIP": null, "MAIL_PLUS_4": null, "MAIL_UNIT_PREFIX": null, "MAIL_UNIT_NUMBER": null, "USE_CODE_MUNI_DESC": null, "USE_CODE_MUNI": null, "USE_CODE_STD_LPS": null, "USE_CODE_STD_DESC_LPS": null, "USE_CODE_STD_CTGR_DESC_LPS": null, "USE_CODE_STD_CTGR_LPS": null, "AGGR_ACREAGE": null, "AGGR_LOT_COUNT": null, "ZONING": null, "BLDG_NUMBER": null, "BUILDING_SQFT": null, "STORIES_NUMBER": null, "STORIES_NUMBER_DESC": null, "TOTAL_ROOMS": null, "UNITS_NUMBER": null, "PARKING_SPACES": null, "BLDG_CLASS": null, "BLDG_CLASS_DESC": null, "CONSTRUCTION_CODE": null, "CONSTRUCTION_CODE_DESC": null, "EXTERIOR_WALL_TYPE": null, "EXTERIOR_WALL_DESC": null, "ROOF_COVER_TYPE": null, "ROOF_COVER_DESC": null, "LOCATION_ID": "US_08_009_XXX5168237061", "PROPERTY_DMP_ID": null, "PARCEL_DMP_ID": "516823706_1", "GEOM": "POLYGON ((-102.56102308 37.05449825, -102.56102664000002 37.061756619999983, -102.54291585 37.061754539999974, -102.54291557 37.058128049999986, -102.55197089 37.05812792, -102.55197016 37.050873270000011, -102.56102013 37.05087081, -102.56102308 37.05449825))" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -102.56102308, 37.05449825 ], [ -102.561026640000023, 37.061756619999983 ], [ -102.54291585, 37.061754539999974 ], [ -102.54291557, 37.058128049999986 ], [ -102.55197089, 37.05812792 ], [ -102.55197016, 37.050873270000011 ], [ -102.56102013, 37.05087081 ], [ -102.56102308, 37.05449825 ] ] ] } },
{ "type": "Feature", "properties": { "FIPS_CODE": 8009, "PARCEL_APN": null, "TAXAPN": null, "SITE_HOUSE_NUMBER": null, "SITE_DIRECTION": null, "SITE_STREET_NAME": null, "SITE_MODE": null, "SITE_QUADRANT": null, "SITE_UNIT_PREFIX": null, "SITE_UNIT_NUMBER": null, "SITE_CITY": null, "SITE_STATE": null, "SITE_ZIP": null, "SITE_PLUS_4": null, "_X_COORD": -102.737556, "_Y_COORD": 37.156019, "ADDR_SCORE": null, "OWNER_NAME_1": null, "OWNER_NAME_2": null, "MAIL_HOUSE_NUMBER": null, "MAIL_DIRECTION": null, "MAIL_STREET_NAME": null, "MAIL_MODE": null, "MAIL_QUADRANT": null, "MAIL_CITY": null, "MAIL_STATE": null, "MAIL_ZIP": null, "MAIL_PLUS_4": null, "MAIL_UNIT_PREFIX": null, "MAIL_UNIT_NUMBER": null, "USE_CODE_MUNI_DESC": null, "USE_CODE_MUNI": null, "USE_CODE_STD_LPS": null, "USE_CODE_STD_DESC_LPS": null, "USE_CODE_STD_CTGR_DESC_LPS": null, "USE_CODE_STD_CTGR_LPS": null, "AGGR_ACREAGE": null, "AGGR_LOT_COUNT": null, "ZONING": null, "BLDG_NUMBER": null, "BUILDING_SQFT": null, "STORIES_NUMBER": null, "STORIES_NUMBER_DESC": null, "TOTAL_ROOMS": null, "UNITS_NUMBER": null, "PARKING_SPACES": null, "BLDG_CLASS": null, "BLDG_CLASS_DESC": null, "CONSTRUCTION_CODE": null, "CONSTRUCTION_CODE_DESC": null, "EXTERIOR_WALL_TYPE": null, "EXTERIOR_WALL_DESC": null, "ROOF_COVER_TYPE": null, "ROOF_COVER_DESC": null, "LOCATION_ID": "US_08_009_XXX5168237062", "PROPERTY_DMP_ID": null, "PARCEL_DMP_ID": "516823706_2", "GEOM": "POLYGON ((-102.7330126 37.148770959999979, -102.74207003 37.148767860000021, -102.74210194 37.16326582, -102.73304057000001 37.16326841, -102.7330126 37.148770959999979))" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -102.7330126, 37.148770959999979 ], [ -102.74207003, 37.148767860000021 ], [ -102.74210194, 37.16326582 ], [ -102.733040570000014, 37.16326841 ], [ -102.7330126, 37.148770959999979 ] ] ] } },
{ "type": "Feature", "properties": { "FIPS_CODE": 8009, "PARCEL_APN": null, "TAXAPN": null, "SITE_HOUSE_NUMBER": null, "SITE_DIRECTION": null, "SITE_STREET_NAME": null, "SITE_MODE": null, "SITE_QUADRANT": null, "SITE_UNIT_PREFIX": null, "SITE_UNIT_NUMBER": null, "SITE_CITY": null, "SITE_STATE": null, "SITE_ZIP": null, "SITE_PLUS_4": null, "_X_COORD": -102.81506, "_Y_COORD": 37.004085, "ADDR_SCORE": null, "OWNER_NAME_1": null, "OWNER_NAME_2": null, "MAIL_HOUSE_NUMBER": null, "MAIL_DIRECTION": null, "MAIL_STREET_NAME": null, "MAIL_MODE": null, "MAIL_QUADRANT": null, "MAIL_CITY": null, "MAIL_STATE": null, "MAIL_ZIP": null, "MAIL_PLUS_4": null, "MAIL_UNIT_PREFIX": null, "MAIL_UNIT_NUMBER": null, "USE_CODE_MUNI_DESC": null, "USE_CODE_MUNI": null, "USE_CODE_STD_LPS": null, "USE_CODE_STD_DESC_LPS": null, "USE_CODE_STD_CTGR_DESC_LPS": null, "USE_CODE_STD_CTGR_LPS": null, "AGGR_ACREAGE": null, "AGGR_LOT_COUNT": null, "ZONING": null, "BLDG_NUMBER": null, "BUILDING_SQFT": null, "STORIES_NUMBER": null, "STORIES_NUMBER_DESC": null, "TOTAL_ROOMS": null, "UNITS_NUMBER": null, "PARKING_SPACES": null, "BLDG_CLASS": null, "BLDG_CLASS_DESC": null, "CONSTRUCTION_CODE": null, "CONSTRUCTION_CODE_DESC": null, "EXTERIOR_WALL_TYPE": null, "EXTERIOR_WALL_DESC": null, "ROOF_COVER_TYPE": null, "ROOF_COVER_DESC": null, "LOCATION_ID": "US_08_009_XXX5168237063", "PROPERTY_DMP_ID": null, "PARCEL_DMP_ID": "516823706_3", "GEOM": "MULTIPOLYGON (((-102.8144019 37.000220300000024, -102.81440001 37.003712959999973, -102.80987063 37.0037188, -102.80987594 37.000216500000022, -102.80534993 37.000142429999983, -102.79628788000002 37.000114470000028, -102.79628782 36.999781059999975, -102.80082103000001 36.99990944000001, -102.80401110000003 37.000001709999985, -102.809876 37.000180469999968, -102.81285284 37.000269880000019, -102.8144019 37.000220300000024)), ((-102.81440001 37.003712959999973, -102.8152316 37.00371293, -102.81522985 37.00734288000001, -102.81439467000001 37.007342709999989, -102.81440001 37.003712959999973)), ((-102.82868814 37.01459485, -102.8324637 37.014591250000024, -102.83246369 37.014663750000011, -102.82794237000002 37.014704750000021, -102.82794456 37.010969900000021, -102.82861387000003 37.01096972, -102.82868814 37.01459485)), ((-102.83246474 37.00738149, -102.83298162 37.007378249999988, -102.8330751 37.010969139999986, -102.83246423000001 37.010968670000011, -102.83246474 37.00738149)), ((-102.84676076 37.01446194, -102.84676385 37.014609619999987, -102.84604829 37.01460972000001, -102.8460482 37.01447282, -102.84676076 37.01446194)), ((-102.83734745 37.01097245, -102.83699172000001 37.010976860000028, -102.83699172000001 37.010972190000018, -102.83734745 37.01097245)), ((-102.83760191 37.010972639999977, -102.83734745 37.01097245, -102.83760182 37.0109693, -102.83760191 37.010972639999977)))" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -102.8144019, 37.000220300000024 ], [ -102.81440001, 37.003712959999973 ], [ -102.80987063, 37.0037188 ], [ -102.80987594, 37.000216500000022 ], [ -102.80534993, 37.000142429999983 ], [ -102.796287880000023, 37.000114470000028 ], [ -102.79628782, 36.999781059999975 ], [ -102.80082103, 36.99990944000001 ], [ -102.804011100000025, 37.000001709999985 ], [ -102.809876, 37.000180469999968 ], [ -102.81285284, 37.000269880000019 ], [ -102.8144019, 37.000220300000024 ] ] ], [ [ [ -102.81440001, 37.003712959999973 ], [ -102.8152316, 37.00371293 ], [ -102.81522985, 37.00734288000001 ], [ -102.814394670000013, 37.007342709999989 ], [ -102.81440001, 37.003712959999973 ] ] ], [ [ [ -102.82868814, 37.01459485 ], [ -102.8324637, 37.014591250000024 ], [ -102.83246369, 37.014663750000011 ], [ -102.827942370000017, 37.014704750000021 ], [ -102.82794456, 37.010969900000021 ], [ -102.828613870000027, 37.01096972 ], [ -102.82868814, 37.01459485 ] ] ], [ [ [ -102.83246474, 37.00738149 ], [ -102.83298162, 37.007378249999988 ], [ -102.8330751, 37.010969139999986 ], [ -102.832464230000014, 37.010968670000011 ], [ -102.83246474, 37.00738149 ] ] ], [ [ [ -102.84676076, 37.01446194 ], [ -102.84676385, 37.014609619999987 ], [ -102.84604829, 37.01460972000001 ], [ -102.8460482, 37.01447282 ], [ -102.84676076, 37.01446194 ] ] ], [ [ [ -102.83734745, 37.01097245 ], [ -102.836991720000015, 37.010976860000028 ], [ -102.836991720000015, 37.010972190000018 ], [ -102.83734745, 37.01097245 ] ] ], [ [ [ -102.83760191, 37.010972639999977 ], [ -102.83734745, 37.01097245 ], [ -102.83760182, 37.0109693 ], [ -102.83760191, 37.010972639999977 ] ] ] ] } },

One more thing I have tried, in the browser console, I tried to import a pbf:

datasource = new atlas.source.VectorTileSource(null, { tiles: [http://127.0.0.1:8080/api/file/5/1/13.pbf'], maxZoom:12});

I get back an Object, and when I try to build the layer with:

var buildingLayer = new atlas.layer.PolygonLayer(datasource, null { sourceLayer: 'Feature', fillColor: 'red', fillOpacity: 0.7});

I get undefined.


Solution

  • Ok, I've found the couple of mistakes I've made. Thanks to @rbrundritt for his suggestions, and to the points I had to investigate.

    I used a different geojson polygon set (MS Building Footprint) to test generated tippecanoe files.

    Before I was running something like:

    tippecanoe --no-feature-limit --no-tile-size-limit --exclude-all --minimum-zoom=5 --maximum-zoom=g --output-to-directory "/home/markus/Documents/AssessorTiles" /home/markus/Documents/Assessor_Json/*.json
    

    The --exclude-all was removing all the columns that had data classification for the polygons (geometry).

    So, I ran the following with the MS Building Footprint:

    tippecanoe --no-feature-limit --no-tile-size-limit --minimum-zoom=2 --no-tile-compression --maximum-zoom=g --output-to-directory "/home/markus/Documents/GA_MicrosoftBuilding" /home/markus/Documents/MS_Building_Footprints_GA_Only/*.json
    

    Now, the MS Building Footprint was a modified one where I included an incremental counter for the each polygon and have the state added.

    Here is the sample of the modified MS Building Footprint json:

        {
    "type": "FeatureCollection",
    "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
    "features": [
    { "type": "Feature", "properties": { "STATE": "GA", "BLDID": 1 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -82.561175, 30.686596 ], [ -82.561175, 30.686414 ], [ -82.560928, 30.686414 ], [ -82.560928, 30.686596 ], [ -82.561175, 30.686596 ] ] ] } },
    { "type": "Feature", "properties": { "STATE": "GA", "BLDID": 2 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -82.570518, 30.683769 ], [ -82.570513, 30.683796 ], [ -82.570401, 30.68378 ], [ -82.570386, 30.683854 ], [ -82.570595, 30.683884 ], [ -82.570615, 30.683783 ], [ -82.570518, 30.683769 ] ] ] } },
    { "type": "Feature", "properties": { "STATE": "GA", "BLDID": 3 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -82.125603, 30.740081 ], [ -82.125472, 30.740081 ], [ -82.125472, 30.740141 ], [ -82.125603, 30.740141 ], [ -82.125603, 30.740081 ] ] ] } },
    { "type": "Feature", "properties": { "STATE": "GA", "BLDID": 4 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -82.075463, 30.737503 ], [ -82.075425, 30.737516 ], [ -82.075433, 30.737534 ], [ -82.075434, 30.737534 ], [ -82.075449, 30.737568 ], [ -82.075487, 30.737555 ], [ -82.075463, 30.737503 ] ] ] } },
    

    The Key plays an important role in reading the PBFs back into azure maps javascript.

    Here is the change I made to azure maps javascript:

                    var buildingLayer = new atlas.layer.PolygonLayer(datasource, null, {
                    sourceLayer: 'GA',
                    fillColor: 'red',
                    fillOpacity: 0.7
                });
                map.layers.add(buildingLayer, 'labels');
    

    So, I used the state key, in this case 'GA' as a sourceLayer in the azure maps javascript.

    Then woola, the vector tiles (PBFs) displays on the map browser.

    That would be great if Microsoft could generate the polygons based on a more generic key. For now, the only solution I see is to add a generic key i.e: 'POLYGON' into the json and rebuild the PBFs.