Alex
Alex

Reputation: 1

How to display the symbols and set "text-field" in a vector tileset using MapBox?

I am trying to display a vector tileset using mapbox gl js. The original data was in KML, and my goal is to display using vector tileset. So I converted the KML to MVT file using GDAL with following command:

 ogr2ogr -f MVT thirdtileset i.kml -dsco COMPRESS=NO -dsco MAXZOOM=15

The output MVT has following structure:

myTileset
   |---0 /* in zxy order */
   |---1
  ...
   |---15
   metadata.json

I was able to display the lines in it using following code:

map.on("load", () => {
   map.addSource("myMap", {
      type: "vector",
      tiles: ["http://127.0.0.1:8080/mytileset/{z}/{x}/{y}.pbf"],
      minzoom: 0,
      maxzoom: 15,
   });

   map.addLayer({
      id: "lineLayer",
      type: "line",
      source: "myMap",
      "source-layer": "mainlayer",
   });
});

But the label contents (text) were missing in the map. I learnt that I need to add a symbol layer and set the "text-field" property. So I tried to figure out what should I put in this field.

Here is my code adding the symbol layer:

map.on("load", () => {
   ... /* same code as above adding source and line layer */
   
   map.addLayer({
      id: "symbolLayer", // Layer ID
         type: "symbol",
         source: "myMap",
         "source-layer": "mainlayer",
         paint: {
            "text-color": "#ff0000",
            "text-opacity": 1,
         },
         layout: {
            "text-field": /* Here is what I am struggling */,
            "text-rotation-alignment": "auto",
            "text-allow-overlap": true,
            "text-anchor": "top",
         },
      }
   );
});

I checked the metadata.json, it has following structure:

{
  "name":"thirdtileset",
  "description":"",
  "version":2,
  "minzoom":0,
  "maxzoom":15,
  "center": /* two numbers in a string split by ',' */,
  "bounds": /* four numbers in a string split by ',' */,
  "type":"overlay",
  "format":"pbf"
  "json":"{\n  \"vector_layers\":[\n ..." /* a very long string of a json file */
}

I copied out the json string in the end and formatted it, and here is its structure:

{
   "vector_layers": [
      {
         "id": /* some layer id */,
         "description": "",
         "minzoom": 0,
         "maxzoom": 15,
         "fields": {
            "Name": "String", // this field contains the string I want to display as label
            ... /* other field, not important */
         }
    },
   ...   /* more layers, but the fields are all the same */
   ...
   ],
   "tilestats": {
   "layerCount": /* some number */,
   "layers": [
      {
         "layer": /* some layer name */,
         "count": /* some number */,
         "geometry": "Point",  /* only points are labels, all points are labels */
         "attributeCount": /* some number */,
         "attributes": [
            {
               "attribute": "Name",
               "count": /* some number */,
               "type": "string",
               "values": [ \* here are the strings of the labels I want to show *\ ]
            },
            {\* some other attributes of other fields *\},
            ...
         ]
      },
      {\* tilestats of another layer *\},
      ...
   ]
}

The strings of the label contents are in

"tilestats" -> "layers"[0, 1, ..., 5] -> "attributes"[0] -> values

I am now struggling to create the "text-field" for it. Any suggestion on how should I compose the "text-field" properties or how to display the labels is appreciated!

I tried to use

["get", "values"]
["get", "Name"]

as text-field value, but neither worked for me. I also tried to write some longer MapBox expressions, but when I printed the symbol layer, the _filterCompiled field is false for all of them, and none of them got the labels to display. I tried to convert the kml to GeoJson, and the labels display simply with ["get", "name"] as "text-field", but I do need to use vector tileset.

Upvotes: 0

Views: 936

Answers (1)

Steve Bennett
Steve Bennett

Reputation: 126617

It's hard to tell for sure since you haven't included your complete code.

But in one place you have written

"source-layer": "mainlayer",

and in another place:

"layer": /* some layer name */,

The value mainLayer needs to match whatever is "some layer name".

Upvotes: 0

Related Questions