3

How can I dynamically add data to a pbf file generated by Maptiler? I created a pbf file with the MapTiler desktop application. I started with a geojson file containing polygon geometries. My file is stored on Maptiler cloud. Maptiler cloud provides this URL to include in my client code.

"https://api.maptiler.com/tiles/28815aac-ebdc-4442-a4b3-62172c26ca52/{z}/{x}/{y}.pbf?key=<myMaptilerKey>";

I am importing the file into my leaflet map like this...

const FOO_PBF =
  "https://api.maptiler.com/tiles/28815aac-ebdc-4442-a4b3-62172c26ca52/{z}/{x}/{y}.pbf?key=<myMaptilerKey>";
  var vectorTileOptions = {
    interactive: true
  };
  var fooLayer = L.vectorGrid.protobuf(
    FOO_PBF,
    vectorTileOptions
  );

  var overlays = {
    FooLayer: fooLayer
  };

The polygons appear correctly. However, I would also like to add data to this layer. Specifically, I have a statistic pertaining to each polygon. I'd like to color the polygons with colors that represent the value of that statistic.

In the past, I imported the geojson file directly into my leaflet map and achieved this "chloropleth" type styling like this.

  var FooLayer= new L.geoJson.ajax(
    "https://raw.githubusercontent.com/...path_to_geojson_file_geo.min.json",
    {
      // style: defaultPolygonStyle,
      onEachFeature: function(feature, layer) {
        layer.bindPopup(
          feature.properties.statisticValue +
            ", " +
            $this.zipData[feature.properties.statisticValue]
        );
        layer.setStyle({
          color: getColorFromRedBlueRange(
            $this.zipData[feature.properties.statisticValue]
          ),
          weight: 0,
          fillOpacity: 0.3
        });
      }
    }
  );

where

  function getColorFromRedBlueRange(d) {
    return d > 0.8
      ? "#FF0000"
      : d > 0.7
      ? "#FF006F"
      : d > 0.55
      ? "#FF00EF"
      : d > 0.45
      ? "#DE00FF"
      : d > 0.3
      ? "#BC00FF"
      : d > 0.2
      ? "#6600FF"
      : "#00009FF";
  }

How can I similary style the polygons in my pbf file? The reason we are using the pbf file rather than the raw geojson is to improve performance by reducing network payload sizes.

With Stefan's tips, I found that this applies the specified yellow fill and red outlines to the polygons in the pbf tile layer...

var vectorTileOptions = {
        interactive: true,
        // pane: "OverlayPane",
        vectorTileLayerStyles: {
          layer_name: {
            fillColor: "yellow",
            fill: true,
            color: "red"
         }
        }
      };

However, if I try to style each polygon according to a statistic in the pbf file, this does not work...

  function getColorFromRedBlueRange2(d) {
    return d == 8
      ? { fillColor: "#FF0000", fill: true, opacity: 1 }
      : d == 7
      ? { fillColor: "#FF006F", fill: true, opacity: 1 }
      : d == 6
      ? { fillColor: "#FF00EF", fill: true, opacity: 1 }
      : d == 5
      ? { fillColor: "#DE00FF", fill: true, opacity: 1 }
      : d == 4
      ? { fillColor: "#BC00FF", fill: true, opacity: 1 }
      : d == 3
      ? { fillColor: "#6600FF", fill: true, opacity: 1 }
      : { fillColor: "#0009FF", fill: true, opacity: 1 };
  }
  var vectorTileOptions = {
    interactive: true,
    // pane: "OverlayPane",
    vectorTileLayerStyles: {
      layer_name: properties => {
        getColorFromRedBlueRange2(properties.SLDUST % 10);
      }
    }
  };

Why not? The SLDUST variable does exist in the properties object and a console.log statement does confirm that this code pulls the SLDUST values from the pbf file.

In both cases, I am adding the layer to the map with this code chunk...

  var pbfLayer = L.vectorGrid.protobuf(
    FOO_PBF,
    vectorTileOptions
  );

2 Answers 2

3

It seems you are using Leaflet VectorGrid for your task. As described in the docs, you must pass the styling in the following form (replace your_layer_name by the actual name of the layer that you specified in Maptiler):

vectorTileOptions = {
  vectorTileLayerStyles: {
    your_layer_name: properties => {
      return getColorFromRedBlueRange(properties.d)
    }
  },
  ...
}

and your getColorFromRedBlueRange(d) function must return L.path options:

function getColorFromRedBlueRange(d) {
  return d > 0.8
      ? {fillColor: "#FF0000"}
      : d > 0.7
      ? {fillColor: "#FF006F"}
      : d > 0.55
      ? {fillColor: "#FF00EF"}
      : d > 0.45
      ? {fillColor: "#DE00FF"}
      : d > 0.3
      ? {fillColor: "#BC00FF"}
      : d > 0.2
      ? {fillColor: "#6600FF"}
      : {fillColor: "#0009FF"}
}

Here is an example from our project:

function trafficLightStyle (match, accuracy, is_highlighted) {
  if (accuracy < CONFIDENCE_THRESHOLD) return {
    fillColor: 'yellow',
    color: 'yellow',
    ...(is_highlighted ? parcel_style_highlighted : parcel_style)
  }
  else if (match === 'True') return {
    fillColor: 'green',
    color: 'green',
    ...(is_highlighted ? parcel_style_highlighted : parcel_style),
  }
  else if (match === 'False') return {
    fillColor: 'red',
    color: 'red',
    ...(is_highlighted ? parcel_style_highlighted : parcel_style)
  }
  else return {
    fillColor: 'grey',
    color: 'grey',
    ...(is_highlighted ? parcel_style_highlighted : parcel_style)
  }
}
2
  • Okay. So if this is the geojson that I uploaded into MapTiler, how can I find my layer name? {"type":"FeatureCollection", "features": [ {"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[-88.154827,42.277588],[-88.154792,42.27653],[-88.15476799999999,42.273148],[-88.154748,42.270252],[-88.154721,42.266346999999996],[-88.15472,42.266183999999996],[-88.154699,42.26305],[-88.154699,42.262994],[-88.154696,42.26257],[-88.154686,42.262248],[-88.15467699999999,42.262145],[-88.154656,42.261899],[-88.1546....
    – GNG
    Commented Jan 21, 2020 at 19:50
  • I am using a Maptiler tile set, not a map. Maybe tile sets do not have layers?
    – GNG
    Commented Jan 21, 2020 at 20:12
0

Here is the solution. Just a matter of syntax. Needed to add the word "return" before "getColorFromRed...." in the tile options object.

  var vectorTileOptions = {
    interactive: true,
    // pane: "OverlayPane",
    vectorTileLayerStyles: {
      layer_name: properties => {
        return getColorFromRedBlueRange2(properties.SLDUST % 10);
      }
    }
  };
1
  • I've edited my answer accordingly. Could you mark my answer as solution? Commented Jan 23, 2020 at 12:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.