go-spatial / tegola

Tegola is a Mapbox Vector Tile server written in Go
http://tegola.io/
MIT License
1.28k stars 196 forks source link

Adding country labels #857

Closed dwoznicki closed 2 years ago

dwoznicki commented 2 years ago

I'd like to add country labels to my map, but I'm not sure how best to do it.

I've found that the "country_polygons" layer contains the country name as metadata, but when I add a text layer to display the country name, I get a lot of extra labels.

In my custom style.json, I've added the following object to my "layers" array.

{    
  "id": "place_name_country",    
  "source": "osm",    
  "source-layer": "country_polygons",    
  "type": "symbol",    
  "layout": {    
    "text-font": [    
      "Open Sans Bold"    
    ],    
    "text-field": "{name}",    
    "text-size": 14,    
    "text-max-width": 6.25,    
    "text-transform": "uppercase"    
  },    
  "paint": {    
    "text-halo-blur": 1,    
    "text-color": "#334",      
    "text-halo-width": 2,    
    "text-halo-color": "rgba(255,255,255,0.8)"    
  }    
}

Loading this into fresco gives me the following:

image

My goal is to have one label per country, similar to how this Mapbox demo does it.

dwoznicki commented 2 years ago

I found a the country_label_points layer in the schema, which sounds pretty promising, but I'm not sure how to use it properly.

The first thing that strikes me is that there seem to be a bunch of label points per country. For example, when I create a purple circle for each label point in the US, here's what I get.

image

My expectation is that there'd be only one country label point for the US; probably somewhere in the middle of the land mass.

Also, the label points appear to use sr_subunit as the label, which does not necessarily contain the full country name.

image

Should I look into changing the schema for this use case?

dwoznicki commented 2 years ago

Just a quick note for myself (and others who might see this later). I found what I was looking for in the OSM data, actually. For example, this query returns the expected result.

osm=# select ST_AsGeoJson(ST_Transform(geometry, 4326)) from osm_place_points where name = 'United States of America';
                         st_asgeojson                         
--------------------------------------------------------------
 {"type":"Point","coordinates":[-100.445882017,39.783730317]}

I'll update if I get get labels working with the Tegola tiles.

dwoznicki commented 2 years ago

For anyone who's interested, I got a proof of concept country labels layer working. Here's what I did:

  1. Added a provider layer for country labels to my tegola.toml file.
    [[providers.layers]]
    name = "country_label_points"
    geometry_fieldname = "geometry"
    id_fieldname = "osm_id"
    sql = "SELECT ST_AsMVTGeom(geometry, !BBOX!) AS geometry, osm_id, name, type, population, tags FROM osm_place_points WHERE type = 'country' AND geometry && !BBOX!"
  1. Added a map layer to add the country label info to my vector tiles (also in tegola.toml).
    [[maps.layers]]
    name = "country_labels"
    provider_layer = "osm.country_label_points"
    min_zoom = 0
    max_zoom = 5
  1. Added a layer to my style.json file to display this labels. This one actually already existed in the hotosm style.json, but I modified it slightly to reference my custom country label layer instead of the default natural earth layer.
{
  "layers": [
    {
      "id": "country_labels",
      "minzoom": 0,
      "maxzoom": 5,
      "type": "symbol",
      "source": "osm",
      "source-layer": "country_labels",
      "layout": {
        "text-font": [
          "Open Sans Bold"
        ],
        "text-size": {
          "stops": [
            [
              3,
              9
            ],
            [
              8,
              14
            ]
          ]
        },
        "text-max-width": {
          "stops": [
            [
              3,
              40
            ],
            [
              8,
              80
            ]
          ]
        },
        "text-letter-spacing": {
          "stops": [
            [
              3,
              0
            ],
            [
              7,
              1
            ],
            [
              8,
              1
            ]
          ]
        },
        "text-field": "{name}"
      },
      "paint": {
        "text-color": "rgba(68, 51, 85, 1)",
        "text-halo-width": 1,
        "text-halo-color": "rgba(255, 255, 255, 1)",
        "text-halo-blur": 38
      }
    }
  ]
}

Here's what it looks like for me. Note that I'm using the hotosm style.json as a starting point, and branching from there.

image