Search code examples
mapboxkmlmapbox-gl-jsmapbox-glvector-tiles

How to only display Placemark names of points in MVT using mapbox?


I am trying to use Mapbox to display a vector tileset. The vector tileset is converted from a kml file. I used gdal to convert it to MVT, and it displays on Mapbox fine, except for one thing: it also shows the name of all lineString points as labels.

A lineString in my kml file has following structure:

<Placemark>
   <name>mainlayer_0</name>
      <Style>
         <LineStyle><color>ffffffff</color><width>1</width></LineStyle>
      </Style>
      <OvStyle>
         <TrackStyle><type>5</type><width>79</width></TrackStyle>
      </OvStyle>
      <LineString>
         <coordinates>
            \* many coordinates *\
         </coordinates>
      </LineString>
</Placemark>

Mapbox shows the "mainlayer_0" as labels, and the same label was put on every single coordinate in the LineString (up to hundreds in each), which is undesired. The only labels I want to show are independent points, with following structure:

<Placemark>
   <name>First Label Name</name>
   <description>I want to show this label</description>
   <Style>
      <IconStyle>
         <Icon>
         </Icon>
         <color>ffffffff</color>
         <scale>1.0</scale>
         </IconStyle>
            <LabelStyle>
               <color>ffffffff</color>
            </LabelStyle>
   </Style>
   <Point>
      <coordinates>/* coordinate of the point */ </coordinates>
   </Point>
</Placemark>

What I did first was converting the kml file into MVT using following command:

ogr2ogr -f MVT output input.kml -dsco COMPRESS=NO -dsco MAXZOOM=15

And display the MVT in mapbox using code below. The lineLayer shows all the lines I need to display. In the symbolLayer, I used ["get", "Name"] to get the text, but the lineString name are also in "Name" field. I think this is the problem, but I do not know how to solve it.

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

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

        map.addLayer({
          id: "symbolLayer",
          type: "symbol",
          source: "map_name",
          "source-layer": "mainlayer",
          layout: {
            "text-field": ["get", "Name"],
            "text-anchor": "top",
          },
        });
      });

With above code, everything looks fine except the names of lineStrings are repetitively displayed on every points in them.

I tried to modify the kml file by replacing all the lineString names to empty string, and the visual outcome met the expectation. However, I need to automate this process and I do not want to manually modify the kml file every time. When MapBox is rendering the labels, I believe it knows if this point is just a point or it is in a LineString, so my questions are:

  1. Is it possible to tell mapbox not to display any labels of a LineString?
  2. Is it possible to tell mapbox to only show name of points?

I also wonder if there is anything I can do in the process of converting kml to MVT that can help with this issue. Any suggestion is appreciated!


Solution

  • This is a bit akward as I found the answer five minutes after I post the question. The answer is one line, adding

    filter: ["==", ["geometry-type"], "Point"],
    

    in map.addLayer({...}). Details can be found here: setFilter

    And an explained usage is here: Filter by geometry-type with new expressions

    Hope this help someone in the future^_^